diff --git a/.gitignore b/.gitignore index f85976819..9e0568225 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,9 @@ *.swp \#* *~ + +.gradle + # IntelliJ files *.eml *.ipr @@ -30,10 +33,18 @@ nbbuild.xml .DS_Store .settings __pycache__ -ant.properties bin + +# Jython specific +ant.properties build +build2 cachedir +.jython_cache dist -target +publications +reports +jffi*.dll + profile.txt +out diff --git a/.hgignore b/.hgignore index 66ef5fbb8..d02b1ae6c 100644 --- a/.hgignore +++ b/.hgignore @@ -8,6 +8,9 @@ syntax: glob *.swp \#* *~ + +.gradle + # IntelliJ files *.eml *.ipr @@ -25,10 +28,18 @@ syntax: glob .DS_Store .settings __pycache__ -ant.properties bin + +# Jython specific +ant.properties build +build2 cachedir +.jython_cache dist +publications +reports +jffi*.dll + profile.txt out diff --git a/.hgtags b/.hgtags index a6d34059e..0fbf348f2 100644 --- a/.hgtags +++ b/.hgtags @@ -101,3 +101,17 @@ d9660aa5cc8af0ce8c839b9712301c180cc4803e v2.7rc1 44403bccae2163186f8ab46b4a544a48e137bba6 v2.7.1b1 6c0da6893570f3ae3cd37a33189cae954e2afebb v2.7.1b2 c3289f2a275446451605e586e5bef70092224184 v2.7.1b3 +03f4808038f8bbc246b6d6a022aecfde087eeb91 v2.7.1rc1 +03f4808038f8bbc246b6d6a022aecfde087eeb91 v2.7.1rc1 +330556fdad478b61f93a548643743c3d0214fd40 v2.7.1rc1 +850c2491cb25a54846ba0aedf70062074b12e673 v2.7.1rc2 +a5a06c9efdb6dd361d5f5c5c1ef07c2ac802e2e0 v2.7.1rc3 +a5a06c9efdb6dd361d5f5c5c1ef07c2ac802e2e0 v2.7.1rc3 +b6e989b788d563b8ecb0c0458ab486fca8d128d6 v2.7.1rc3 +dd7e191d4c90d9f5d5fe8f0840f186697ecf272a v2.7.1 +dfc49bafbe79566bd54c8d417829e001ff2316ea v2.7.2a1 +328e162ec1178fb38b81b342f84c1268bf21d7fb v2.7.2b1 +b9b60766cabebf007b7584ec21a69b3f58587525 v2.7.2b2 +6d3659465010fd2a8fb11a93953bae5bf9e9db80 v2.7.2b3 +1fcef1abf1d66abfef61a365d4fccef158d37fb7 v2.7.2rc1 +925a3cc3b49d8105688dfbec11fe68546b354169 v2.7.2 diff --git a/.travis.yml b/.travis.yml index 3b0390445..792a10bf2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,45 +1,53 @@ language: java -notifications: - email: - recipients: - - jython-dev@lists.sourceforge.net - -install: ant +addons: + hostname: jyshort -os: - - linux - - osx + homebrew: # only active on osx + update: true + packages: + - ant -env: - matrix: - - CUSTOM_JDK="default" - - CUSTOM_JDK="oraclejdk7" - - CUSTOM_JDK="openjdk7" matrix: - exclude: - # On OSX, run with default JDK only. - - os: osx - env: CUSTOM_JDK="oraclejdk7" - - os: osx - env: CUSTOM_JDK="openjdk7" - # On Linux, run with specific JDKs only. - - os: linux - env: CUSTOM_JDK="default" - -before_install: - # Patch for buffer overflow bug, see https://github.com/travis-ci/travis-ci/issues/5227 - - hostname - - cat /etc/hosts # optionally check the content *before* - - sudo hostname "$(hostname | cut -c1-63)" - - sed -e "s/^\\(127\\.0\\.0\\.1.*\\)/\\1 $(hostname | cut -c1-63)/" /etc/hosts | sudo tee /etc/hosts - - hostname - - cat /etc/hosts # optionally check the content *after* - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then export JAVA_HOME=$(/usr/libexec/java_home); fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew update; fi - - if [ "$TRAVIS_OS_NAME" == "osx" ]; then brew install ant; fi - - if [ "$TRAVIS_OS_NAME" == "linux" ]; then jdk_switcher use "$CUSTOM_JDK"; fi - -script: ant && ant regrtest-travis + include: + - os: linux + dist: xenial + addons: + apt: + packages: + - ant + jdk: openjdk8 + + - os: linux + dist: xenial + addons: + apt: + packages: + - ant + jdk: openjdk11 + + - os: linux + dist: xenial + addons: + apt: + packages: + - ant + jdk: openjdk12 + + - os: osx + osx_image: xcode9.3 # Last supporting Java 8 + jdk: oraclejdk8 + + +install: + - ant developer-build + + +script: + - ant regrtest-travis +notifications: + email: + recipients: + - jython-dev@lists.sourceforge.net diff --git a/ACKNOWLEDGMENTS b/ACKNOWLEDGMENTS index 08762e1cc..ef8436447 100644 --- a/ACKNOWLEDGMENTS +++ b/ACKNOWLEDGMENTS @@ -3,7 +3,7 @@ ACKNOWLEDGMENTS Jython: Python for the Java Platform -Copyright (c) 2000-2016 Jython Developers. +Copyright (c) 2000-2018 Jython Developers. All rights reserved. Copyright (c) 2000 BeOpen.com. @@ -31,7 +31,7 @@ Jython links the following libraries: * Jar Jar Links, licensed under the Apache 2.0 License from Tonic Systems * Java Native Runtime, licensed under the Common Public License * JLine2, licensed under a BSD license -* JUnit, licenseed under Eclipse Public License 1.0 from the JUnit project +* JUnit, licensed under Eclipse Public License 1.0 from the JUnit project * Mock Runner, licensed under the Apache 1.1 license * Netty 4, licensed under the Apache 2.0 license from the Netty project * PyPy datetime module, licensed under the MIT License from the PyPy project @@ -176,6 +176,16 @@ Jython in ways large and small, in no particular order: Nick Bailey Doug Clayton Carl Wicklow + James Mudd + Mat Booth + Alex Gaman + Tom Bech + Richie Bendall + Raymond Ferguson + yishenggudou (愧僧) + Andrew Kuchling + Jim Peterson + Christian Clauss Local Variables: mode: indented-text diff --git a/CPythonLib.includes b/CPythonLib.includes index 317c08cec..0caaa7fc7 100644 --- a/CPythonLib.includes +++ b/CPythonLib.includes @@ -110,6 +110,7 @@ mutex.py netrc.py nntplib.py numbers.py +ntpath.py nturl2path.py opcode.py optparse.py diff --git a/CoreExposed.includes b/CoreExposed.includes index 7c7a5f3c8..9f265c1d8 100644 --- a/CoreExposed.includes +++ b/CoreExposed.includes @@ -1,5 +1,7 @@ org/python/core/AstList.class org/python/core/ClasspathPyImporter.class +org/python/core/FloatInfo.class +org/python/core/LongInfo.class org/python/core/Py2kBuffer.class org/python/core/PyArray.class org/python/core/PyBaseString.class @@ -37,9 +39,11 @@ org/python/core/PyMethod.class org/python/core/PyMethodDescr.class org/python/core/PyModule.class org/python/core/PyNone.class +org/python/core/PyNullImporter.class org/python/core/PyObject.class org/python/core/PyProperty.class org/python/core/PySet.class +org/python/core/PyShadowString.class org/python/core/PySlice.class org/python/core/PySlot.class org/python/core/PyStaticMethod.class @@ -53,6 +57,8 @@ org/python/core/PyType.class org/python/core/PyUnicode.class org/python/core/PyVersionInfo.class org/python/core/PyXRange.class +org/python/core/PyXRangeIter.class +org/python/core/WinVersion.class org/python/core/stringlib/MarkupIterator.class org/python/core/stringlib/FieldNameIterator.class org/python/modules/PyStruct.class @@ -68,6 +74,8 @@ org/python/modules/_io/PyRawIOBase.class org/python/modules/_io/PyFileIO.class org/python/modules/_functools/PyPartial.class org/python/modules/_hashlib$Hash.class +org/python/modules/_json/Encoder.class +org/python/modules/_json/Scanner.class org/python/modules/bz2/PyBZ2File.class org/python/modules/bz2/PyBZ2Compressor.class org/python/modules/bz2/PyBZ2Decompressor.class @@ -81,6 +89,7 @@ org/python/modules/itertools/dropwhile.class org/python/modules/itertools/groupby.class org/python/modules/itertools/ifilterfalse.class org/python/modules/itertools/ifilter.class +org/python/modules/itertools/imap.class org/python/modules/itertools/islice.class org/python/modules/itertools/izip.class org/python/modules/itertools/izipLongest.class @@ -95,6 +104,7 @@ org/python/modules/jffi/ByReference.class org/python/modules/jffi/CData.class org/python/modules/jffi/CType.class org/python/modules/jffi/CType$Array.class +org/python/modules/jffi/CType$Custom.class org/python/modules/jffi/CType$Pointer.class org/python/modules/jffi/DynamicLibrary.class org/python/modules/jffi/DynamicLibrary$Symbol.class @@ -166,6 +176,8 @@ org/python/antlr/ast/Print.class org/python/antlr/ast/Raise.class org/python/antlr/ast/Repr.class org/python/antlr/ast/Return.class +org/python/antlr/ast/Set.class +org/python/antlr/ast/SetComp.class org/python/antlr/ast/Slice.class org/python/antlr/ast/Str.class org/python/antlr/ast/Subscript.class diff --git a/Demo/applet/deprecated/ButtonDemo.py b/Demo/applet/deprecated/ButtonDemo.py index 2c34d8903..a81988616 100644 --- a/Demo/applet/deprecated/ButtonDemo.py +++ b/Demo/applet/deprecated/ButtonDemo.py @@ -6,27 +6,28 @@ from java import awt, applet + class ButtonDemo(applet.Applet): def init(self): - self.b1 = awt.Button('Disable middle button', - actionPerformed=self.disable) - self.b2 = awt.Button('Middle button') - self.b3 = awt.Button('Enable middle button', - enabled=0, actionPerformed=self.enable) + self.b1 = awt.Button('Disable middle button', + actionPerformed=self.disable) + self.b2 = awt.Button('Middle button') + self.b3 = awt.Button('Enable middle button', + enabled=0, actionPerformed=self.enable) - self.add(self.b1) - self.add(self.b2) - self.add(self.b3) + self.add(self.b1) + self.add(self.b2) + self.add(self.b3) def enable(self, event): - self.b1.enabled = self.b2.enabled = 1 - self.b3.enabled = 0 + self.b1.enabled = self.b2.enabled = 1 + self.b3.enabled = 0 def disable(self, event): - self.b1.enabled = self.b2.enabled = 0 - self.b3.enabled = 1 + self.b1.enabled = self.b2.enabled = 0 + self.b3.enabled = 1 -if __name__ == '__main__': +if __name__ == '__main__': import pawt pawt.test(ButtonDemo()) diff --git a/Demo/applet/deprecated/ButtonFontDemo.py b/Demo/applet/deprecated/ButtonFontDemo.py index dbf312db1..830118ee2 100644 --- a/Demo/applet/deprecated/ButtonFontDemo.py +++ b/Demo/applet/deprecated/ButtonFontDemo.py @@ -6,28 +6,29 @@ from java import awt, applet + class ButtonFontDemo(applet.Applet): def init(self): - self.font = awt.Font('Serif', 0, 24) - self.b1 = awt.Button('Disable middle button', - actionPerformed=self.disable) - self.b2 = awt.Button('Middle button') - self.b3 = awt.Button('Enable middle button', - enabled=0, actionPerformed=self.enable) + self.font = awt.Font('Serif', 0, 24) + self.b1 = awt.Button('Disable middle button', + actionPerformed=self.disable) + self.b2 = awt.Button('Middle button') + self.b3 = awt.Button('Enable middle button', + enabled=0, actionPerformed=self.enable) - self.add(self.b1) - self.add(self.b2) - self.add(self.b3) + self.add(self.b1) + self.add(self.b2) + self.add(self.b3) def enable(self, event): - self.b1.enabled = self.b2.enabled = 1 - self.b3.enabled = 0 + self.b1.enabled = self.b2.enabled = 1 + self.b3.enabled = 0 def disable(self, event): - self.b1.enabled = self.b2.enabled = 0 - self.b3.enabled = 1 + self.b1.enabled = self.b2.enabled = 0 + self.b3.enabled = 1 -if __name__ == '__main__': +if __name__ == '__main__': import pawt pawt.test(ButtonFontDemo()) diff --git a/Demo/applet/deprecated/CheckboxDemo.py b/Demo/applet/deprecated/CheckboxDemo.py index bfbbede0b..7d6c3c4c4 100644 --- a/Demo/applet/deprecated/CheckboxDemo.py +++ b/Demo/applet/deprecated/CheckboxDemo.py @@ -6,36 +6,36 @@ from java import awt, applet + class CheckboxDemo(applet.Applet): def init(self): - cb1 = awt.Checkbox('Checkbox 1') - cb2 = awt.Checkbox('Checkbox 2') - cb3 = awt.Checkbox('Checkbox 3', state=1) + cb1 = awt.Checkbox('Checkbox 1') + cb2 = awt.Checkbox('Checkbox 2') + cb3 = awt.Checkbox('Checkbox 3', state=1) - p1 = awt.Panel(layout=awt.FlowLayout()) + p1 = awt.Panel(layout=awt.FlowLayout()) - p1.add(cb1) - p1.add(cb2) - p1.add(cb3) + p1.add(cb1) + p1.add(cb2) + p1.add(cb3) - cbg = awt.CheckboxGroup() - cb4 = awt.Checkbox('Checkbox 4', cbg, 0) - cb5 = awt.Checkbox('Checkbox 5', cbg, 0) - cb6 = awt.Checkbox('Checkbox 6', cbg, 0) + cbg = awt.CheckboxGroup() + cb4 = awt.Checkbox('Checkbox 4', cbg, 0) + cb5 = awt.Checkbox('Checkbox 5', cbg, 0) + cb6 = awt.Checkbox('Checkbox 6', cbg, 0) - p2 = awt.Panel(layout=awt.FlowLayout()) - p2.add(cb4) - p2.add(cb5) - p2.add(cb6) + p2 = awt.Panel(layout=awt.FlowLayout()) + p2.add(cb4) + p2.add(cb5) + p2.add(cb6) - self.setLayout(awt.GridLayout(0, 2)) - self.add(p1) - self.add(p2) + self.setLayout(awt.GridLayout(0, 2)) + self.add(p1) + self.add(p2) - self.validate() + self.validate() -if __name__ == '__main__': +if __name__ == '__main__': import pawt pawt.test(CheckboxDemo()) - diff --git a/Demo/applet/deprecated/ChoiceDemo.py b/Demo/applet/deprecated/ChoiceDemo.py index 623235d7e..22de0b24f 100644 --- a/Demo/applet/deprecated/ChoiceDemo.py +++ b/Demo/applet/deprecated/ChoiceDemo.py @@ -6,21 +6,22 @@ from java import awt, applet -class ChoiceDemo(applet.Applet): + +class ChoiceDemo(applet.Applet): def init(self): - self.choices = awt.Choice(itemStateChanged = self.change) - for item in ['ichi', 'ni', 'san', 'yon']: - self.choices.addItem(item) + self.choices = awt.Choice(itemStateChanged=self.change) + for item in ['ichi', 'ni', 'san', 'yon']: + self.choices.addItem(item) - self.label = awt.Label() - self.change() + self.label = awt.Label() + self.change() - self.add(self.choices) - self.add(self.label) + self.add(self.choices) + self.add(self.label) def change(self, event=None): - selection = self.choices.selectedIndex, self.choices.selectedItem - self.label.text = 'Item #%d selected. Text = "%s".' % selection + selection = self.choices.selectedIndex, self.choices.selectedItem + self.label.text = 'Item #%d selected. Text = "%s".' % selection if __name__ == '__main__': diff --git a/Demo/applet/deprecated/Converter.py b/Demo/applet/deprecated/Converter.py index f13901bb0..150901e7e 100644 --- a/Demo/applet/deprecated/Converter.py +++ b/Demo/applet/deprecated/Converter.py @@ -10,102 +10,98 @@ from pawt import GridBag basicUnits = [['Metric System', [('Centimeters', 0.01), - ('Meters', 1.0), - ('Kilometers', 1000.0)]], - ['U.S. System', [('Inches', 0.0254), - ('Feet', 0.305), - ('Yards', 0.914), - ('Miles', 1613.0)]] - ] - + ('Meters', 1.0), + ('Kilometers', 1000.0)]], + ['U.S. System', [('Inches', 0.0254), + ('Feet', 0.305), + ('Yards', 0.914), + ('Miles', 1613.0)]] + ] class SimpleBorder: def paint(self, g): - g.drawRect(0,0,self.size.width-1, self.size.height-1) + g.drawRect(0, 0, self.size.width-1, self.size.height-1) def getInsets(self): - return awt.Insets(5,5,5,5) - + return awt.Insets(5, 5, 5, 5) class Converter(Applet, SimpleBorder): def init(self, unitSets=basicUnits): - self.setLayout(awt.GridLayout(2,0,5,5)) - self.panels = [] - for name, units in unitSets: - panel = ConversionPanel(name, units, self) - self.panels.append(panel) - self.add(panel) + self.setLayout(awt.GridLayout(2, 0, 5, 5)) + self.panels = [] + for name, units in unitSets: + panel = ConversionPanel(name, units, self) + self.panels.append(panel) + self.add(panel) def convert(self, master): - value = master.getValue() - multiplier = master.getMultiplier() - - for panel in self.panels: - if panel is not master: - panel.setValue(multiplier/panel.getMultiplier()*value) + value = master.getValue() + multiplier = master.getMultiplier() + for panel in self.panels: + if panel is not master: + panel.setValue(multiplier/panel.getMultiplier()*value) class ConversionPanel(awt.Panel, SimpleBorder, - ActionListener, AdjustmentListener, ItemListener): + ActionListener, AdjustmentListener, ItemListener): max, block = 10000, 100 def __init__(self, title, units, controller): - self.units = units - self.controller = controller + self.units = units + self.controller = controller - bag = GridBag(self, fill='HORIZONTAL') + bag = GridBag(self, fill='HORIZONTAL') - label = awt.Label(title, awt.Label.CENTER) - bag.addRow(label) + label = awt.Label(title, awt.Label.CENTER) + bag.addRow(label) - self.text = awt.TextField('0', 10, actionListener=self) - bag.add(self.text, weightx=1.0) + self.text = awt.TextField('0', 10, actionListener=self) + bag.add(self.text, weightx=1.0) - self.chooser = awt.Choice(itemListener=self) - for name, multiplier in units: - self.chooser.add(name) - bag.addRow(self.chooser) + self.chooser = awt.Choice(itemListener=self) + for name, multiplier in units: + self.chooser.add(name) + bag.addRow(self.chooser) - self.slider = awt.Scrollbar(awt.Scrollbar.HORIZONTAL, - maximum=self.max+10, - blockIncrement=self.block, - adjustmentListener=self) - bag.add(self.slider) + self.slider = awt.Scrollbar(awt.Scrollbar.HORIZONTAL, + maximum=self.max+10, + blockIncrement=self.block, + adjustmentListener=self) + bag.add(self.slider) def getMultiplier(self): - return self.units[self.chooser.selectedIndex][1] + return self.units[self.chooser.selectedIndex][1] def getValue(self): - try: - return float(self.text.getText()) - except: - return 0.0 + try: + return float(self.text.getText()) + except: + return 0.0 def actionPerformed(self, e): - self.setSlider(self.getValue()) - self.controller.convert(self) + self.setSlider(self.getValue()) + self.controller.convert(self) def itemStateChanged(self, e): - self.controller.convert(self) + self.controller.convert(self) def adjustmentValueChanged(self, e): - self.text.setText(str(e.getValue())) - self.controller.convert(self) + self.text.setText(str(e.getValue())) + self.controller.convert(self) def setValue(self, v): - self.text.setText(str(v)) - self.setSlider(v) + self.text.setText(str(v)) + self.setSlider(v) def setSlider(self, f): - if f > self.max: - f = self.max - if f < 0: - f = 0 - self.slider.value = int(f) - + if f > self.max: + f = self.max + if f < 0: + f = 0 + self.slider.value = int(f) if __name__ == '__main__': diff --git a/Demo/applet/deprecated/CoordinatesDemo.py b/Demo/applet/deprecated/CoordinatesDemo.py index 4fbc221de..cacc3c27c 100644 --- a/Demo/applet/deprecated/CoordinatesDemo.py +++ b/Demo/applet/deprecated/CoordinatesDemo.py @@ -10,58 +10,55 @@ class CoordinatesDemo(applet.Applet): def init(self): - bag = GridBag(self) + bag = GridBag(self) - self.framedArea = FramedArea(self) - bag.addRow(self.framedArea, weighty=1.0, fill='BOTH') + self.framedArea = FramedArea(self) + bag.addRow(self.framedArea, weighty=1.0, fill='BOTH') - self.label = awt.Label('Click within the framed area') - bag.addRow(self.label, weightx=1.0, weighty=0.0, fill='HORIZONTAL') + self.label = awt.Label('Click within the framed area') + bag.addRow(self.label, weightx=1.0, weighty=0.0, fill='HORIZONTAL') def updateLabel(self, point): - text = 'Click occurred at coordinate (%d, %d).' - self.label.text = text % (point.x, point.y) - + text = 'Click occurred at coordinate (%d, %d).' + self.label.text = text % (point.x, point.y) class FramedArea(awt.Panel): def __init__(self, controller): - self.background = awt.Color.lightGray - self.setLayout(awt.GridLayout(1,0)) + self.background = awt.Color.lightGray + self.setLayout(awt.GridLayout(1, 0)) - self.add(CoordinateArea(controller)) + self.add(CoordinateArea(controller)) def getInsets(self): - return awt.Insets(4,4,5,5) + return awt.Insets(4, 4, 5, 5) def paint(self, g): - d = self.size - - g.color = self.background - g.draw3DRect(0, 0, d.width-1, d.height-1, 1) - g.draw3DRect(3, 3, d.width-7, d.height-7, 1) + d = self.size + g.color = self.background + g.draw3DRect(0, 0, d.width-1, d.height-1, 1) + g.draw3DRect(3, 3, d.width-7, d.height-7, 1) class CoordinateArea(awt.Canvas): def __init__(self, controller): - self.mousePressed = self.push - self.controller = controller + self.mousePressed = self.push + self.controller = controller def push(self, e): - try: - self.point.x = e.x - self.point.y = e.y - except AttributeError: - self.point = awt.Point(e.x, e.y) + try: + self.point.x = e.x + self.point.y = e.y + except AttributeError: + self.point = awt.Point(e.x, e.y) - self.repaint() + self.repaint() def paint(self, g): - if hasattr(self, 'point'): - self.controller.updateLabel(self.point) - g.fillRect(self.point.x-1, self.point.y-1, 2, 2) - + if hasattr(self, 'point'): + self.controller.updateLabel(self.point) + g.fillRect(self.point.x-1, self.point.y-1, 2, 2) if __name__ == '__main__': diff --git a/Demo/applet/deprecated/HelloApplet.py b/Demo/applet/deprecated/HelloApplet.py index 97b7e984e..78430475f 100644 --- a/Demo/applet/deprecated/HelloApplet.py +++ b/Demo/applet/deprecated/HelloApplet.py @@ -19,10 +19,11 @@ from java import awt, applet + class HelloApplet(applet.Applet): def paint(self, g): - g.setColor(awt.Color.black) - g.fill3DRect(5,5,590,100,0) - g.setFont(awt.Font('Arial', 0, 80)) - g.setColor(awt.Color.blue) - g.drawString('Hello World', 90, 80) + g.setColor(awt.Color.black) + g.fill3DRect(5, 5, 590, 100, 0) + g.setFont(awt.Font('Arial', 0, 80)) + g.setColor(awt.Color.blue) + g.drawString('Hello World', 90, 80) diff --git a/Demo/applet/deprecated/HelloWorld.py b/Demo/applet/deprecated/HelloWorld.py index fc17d5388..3f1b53385 100644 --- a/Demo/applet/deprecated/HelloWorld.py +++ b/Demo/applet/deprecated/HelloWorld.py @@ -1,9 +1,10 @@ from java.applet import Applet import sys + class HelloWorld(Applet): def paint(self, g): - g.drawString("Hello from Jython %s!" % sys.version, 20, 30) + g.drawString("Hello from Jython %s!" % sys.version, 20, 30) if __name__ == '__main__': diff --git a/Demo/applet/deprecated/LabelDemo.py b/Demo/applet/deprecated/LabelDemo.py index 9c519e626..b2ad41140 100644 --- a/Demo/applet/deprecated/LabelDemo.py +++ b/Demo/applet/deprecated/LabelDemo.py @@ -7,12 +7,13 @@ from java import applet from java.awt import Label, GridLayout -class LabelDemo(applet.Applet): + +class LabelDemo(applet.Applet): def init(self): - self.setLayout(GridLayout(0,1)) - self.add(Label('Left')) - self.add(Label('Center', Label.CENTER)) - self.add(Label('Right', Label.RIGHT)) + self.setLayout(GridLayout(0, 1)) + self.add(Label('Left')) + self.add(Label('Center', Label.CENTER)) + self.add(Label('Right', Label.RIGHT)) if __name__ == '__main__': diff --git a/Demo/applet/deprecated/ListDemo.py b/Demo/applet/deprecated/ListDemo.py index f1dd3e51e..38735ded9 100644 --- a/Demo/applet/deprecated/ListDemo.py +++ b/Demo/applet/deprecated/ListDemo.py @@ -8,49 +8,50 @@ from java.awt.event import ItemEvent from pawt import GridBag + class ListDemo(applet.Applet): def fillList(self, list, names): - list.actionPerformed=self.action - list.itemStateChanged=self.change + list.actionPerformed = self.action + list.itemStateChanged = self.change - for name in names: - list.add(name) + for name in names: + list.add(name) def init(self): - self.spanish = awt.List(4, 1) - self.fillList(self.spanish, ['uno', 'dos', 'tres', 'cuatro', - 'cinco', 'seis', 'siete']) - self.italian = awt.List() - self.fillList(self.italian, ['uno', 'due', 'tre', 'quattro', - 'cinque', 'sei', 'sette']) + self.spanish = awt.List(4, 1) + self.fillList(self.spanish, ['uno', 'dos', 'tres', 'cuatro', + 'cinco', 'seis', 'siete']) + self.italian = awt.List() + self.fillList(self.italian, ['uno', 'due', 'tre', 'quattro', + 'cinque', 'sei', 'sette']) - self.output = awt.TextArea(10, 40, editable=0) + self.output = awt.TextArea(10, 40, editable=0) - bag = GridBag(self) - bag.add(self.output, - fill='BOTH', weightx=1.0, weighty=1.0, - gridheight=2) + bag = GridBag(self) + bag.add(self.output, + fill='BOTH', weightx=1.0, weighty=1.0, + gridheight=2) - bag.addRow(self.spanish, fill='VERTICAL') - bag.addRow(self.italian, fill='VERTICAL') + bag.addRow(self.spanish, fill='VERTICAL') + bag.addRow(self.italian, fill='VERTICAL') - self.language = {self.spanish:'Spanish', self.italian:'Italian'} + self.language = {self.spanish: 'Spanish', self.italian: 'Italian'} def action(self, e): - list = e.source - text = 'Action event occurred on "%s" in %s.\n' - self.output.append(text % (list.selectedItem, self.language[list])) + list = e.source + text = 'Action event occurred on "%s" in %s.\n' + self.output.append(text % (list.selectedItem, self.language[list])) def change(self, e): - list = e.source - if e.stateChange == ItemEvent.SELECTED: - select = 'Select' - else: - select = 'Deselect' - - text = '%s event occurred on item #%d (%s) in %s.\n' - params = (select, e.item, list.getItem(e.item), self.language[list]) - self.output.append(text % params) + list = e.source + if e.stateChange == ItemEvent.SELECTED: + select = 'Select' + else: + select = 'Deselect' + + text = '%s event occurred on item #%d (%s) in %s.\n' + params = (select, e.item, list.getItem(e.item), self.language[list]) + self.output.append(text % params) if __name__ == '__main__': diff --git a/Demo/awt/Colors.py b/Demo/awt/Colors.py index 38bb2ebc0..4f9106dff 100644 --- a/Demo/awt/Colors.py +++ b/Demo/awt/Colors.py @@ -9,11 +9,12 @@ p = awt.Panel() for name in dir(colors): - color = getattr(colors, name) - if isinstance(color, awt.Color): - l = awt.Label(name, awt.Label.CENTER, background=color) - intensity = sqrt(color.red**2 + color.green**2 + color.blue**2)/3 - if intensity < 90: l.foreground = colors.white - p.add(l) + color = getattr(colors, name) + if isinstance(color, awt.Color): + l = awt.Label(name, awt.Label.CENTER, background=color) + intensity = sqrt(color.red**2 + color.green**2 + color.blue**2)/3 + if intensity < 90: + l.foreground = colors.white + p.add(l) -test(p, size=(700,500)) \ No newline at end of file +test(p, size=(700, 500)) diff --git a/Demo/awt/Graph.py b/Demo/awt/Graph.py index c183b29e7..479a3d761 100644 --- a/Demo/awt/Graph.py +++ b/Demo/awt/Graph.py @@ -2,62 +2,64 @@ from math import * from jarray import array + class Graph(awt.Canvas): - def __init__(self): - self.function = None - - def paint(self, g): - if self.function is None: - return self.error(g) - - sz = self.size - xs = range(0, sz.width, 2) - - xscale = 4*pi/sz.width - xoffset = -2*pi - - yscale = -sz.height/2. - yoffset = sz.height/2. - - ys = [] - for x in xs: - x = xscale*x + xoffset - y = int(yscale*self.function(x)+yoffset) - ys.append(y) - g.drawPolyline(array(xs, 'i'), array(ys, 'i'), len(xs)) - - def error(self, g): - message = "Invalid Expression" - g.font = awt.Font('Serif', awt.Font.BOLD, 20) - width = g.fontMetrics.stringWidth(message) - - x = (self.size.width-width)/2 - y = (self.size.height+g.fontMetrics.height)/2 - g.drawString("Invalid Expression", x, y) - - def setExpression(self, e): - "@sig public void setExpression(java.lang.String e)" - try: - self.function = eval('lambda x: '+e) - except: - self.function = None - self.repaint() - + def __init__(self): + self.function = None + + def paint(self, g): + if self.function is None: + return self.error(g) + + sz = self.size + xs = range(0, sz.width, 2) + + xscale = 4*pi/sz.width + xoffset = -2*pi + + yscale = -sz.height/2. + yoffset = sz.height/2. + + ys = [] + for x in xs: + x = xscale*x + xoffset + y = int(yscale*self.function(x)+yoffset) + ys.append(y) + g.drawPolyline(array(xs, 'i'), array(ys, 'i'), len(xs)) + + def error(self, g): + message = "Invalid Expression" + g.font = awt.Font('Serif', awt.Font.BOLD, 20) + width = g.fontMetrics.stringWidth(message) + + x = (self.size.width-width)/2 + y = (self.size.height+g.fontMetrics.height)/2 + g.drawString("Invalid Expression", x, y) + + def setExpression(self, e): + "@sig public void setExpression(java.lang.String e)" + try: + self.function = eval('lambda x: '+e) + except: + self.function = None + self.repaint() + if __name__ == '__main__': - def enter(e): - graph.setExpression(expression.text) - expression.caretPosition=0 - expression.selectAll() - - p = awt.Panel(layout=awt.BorderLayout()) - graph = Graph() - p.add(graph, 'Center') - - expression = awt.TextField(text='(sin(3*x)+cos(x))/2', actionPerformed=enter) - p.add(expression, 'South') - - import pawt - pawt.test(p, size=(300,300)) - - enter(None) + def enter(e): + graph.setExpression(expression.text) + expression.caretPosition = 0 + expression.selectAll() + + p = awt.Panel(layout=awt.BorderLayout()) + graph = Graph() + p.add(graph, 'Center') + + expression = awt.TextField( + text='(sin(3*x)+cos(x))/2', actionPerformed=enter) + p.add(expression, 'South') + + import pawt + pawt.test(p, size=(300, 300)) + + enter(None) diff --git a/Demo/awt/simple.py b/Demo/awt/simple.py index c309ce056..0de133973 100644 --- a/Demo/awt/simple.py +++ b/Demo/awt/simple.py @@ -9,8 +9,10 @@ import java from java import awt + def exit(e): java.lang.System.exit(0) + frame = awt.Frame('AWT Example', visible=1) button = awt.Button('Close Me!', actionPerformed=exit) frame.add(button, 'Center') diff --git a/Demo/bean/TempConverter.py b/Demo/bean/TempConverter.py index 10ae7ab2f..38bfdf74b 100644 --- a/Demo/bean/TempConverter.py +++ b/Demo/bean/TempConverter.py @@ -1,36 +1,38 @@ import java + class TempConverter(java.lang.Object): - def __init__(self): - self.setFahrenheit(0.0) + def __init__(self): + self.setFahrenheit(0.0) + + def setFahrenheit(self, degrees): + "@sig public void setFahrenheit(double degrees)" + self.f = degrees + self.c = (degrees-32.)/1.8 - def setFahrenheit(self, degrees): - "@sig public void setFahrenheit(double degrees)" - self.f = degrees - self.c = (degrees-32.)/1.8 + def getFahrenheit(self): + "@sig public double getFahrenheit()" + return self.f - def getFahrenheit(self): - "@sig public double getFahrenheit()" - return self.f + def setCelsius(self, degrees): + "@sig public void setCelsius(double degrees)" + self.c = degrees + self.f = degrees*1.8+32. - def setCelsius(self, degrees): - "@sig public void setCelsius(double degrees)" - self.c = degrees - self.f = degrees*1.8+32. + def getCelsius(self): + "@sig public double getCelsius()" + return self.c - def getCelsius(self): - "@sig public double getCelsius()" - return self.c + def __repr__(self): + return '<%.2g degrees fahrenheit == %.2g celsius>' % (self.f, self.c) - def __repr__(self): - return '<%.2g degrees fahrenheit == %.2g celsius>' % (self.f, self.c) if __name__ == '__main__': - c = TempConverter() - print c - c.setCelsius(100) - print c - c.setCelsius(0) - print c - c.setFahrenheit(212) - print c \ No newline at end of file + c = TempConverter() + print c + c.setCelsius(100) + print c + c.setCelsius(0) + print c + c.setFahrenheit(212) + print c diff --git a/Demo/javaclasses/deprecated/Graph.py b/Demo/javaclasses/deprecated/Graph.py index 645ca936d..78b7e2b02 100644 --- a/Demo/javaclasses/deprecated/Graph.py +++ b/Demo/javaclasses/deprecated/Graph.py @@ -2,65 +2,67 @@ from math import * from jarray import array + class Graph(awt.Canvas): - def __init__(self, initialExpression=None): - "@sig public Graph(java.lang.String initialExpression)" - self.function = None - if initialExpression is not None: - self.setExpression(initialExpression) - - def paint(self, g): - if self.function is None: - return self.error(g) - - sz = self.size - xs = range(0, sz.width, 2) - - xscale = 4*pi/sz.width - xoffset = -2*pi - - yscale = -sz.height/2. - yoffset = sz.height/2. - - ys = [] - for x in xs: - x = xscale*x + xoffset - y = int(yscale*self.function(x)+yoffset) - ys.append(y) - g.drawPolyline(array(xs, 'i'), array(ys, 'i'), len(xs)) - - def error(self, g): - message = "Invalid Expression" - g.font = awt.Font('Serif', awt.Font.BOLD, 20) - width = g.fontMetrics.stringWidth(message) - - x = (self.size.width-width)/2 - y = (self.size.height+g.fontMetrics.height)/2 - g.drawString("Invalid Expression", x, y) - - def setExpression(self, e): - "@sig public void setExpression(java.lang.String e)" - try: - self.function = eval('lambda x: '+e) - except: - self.function = None - self.repaint() - + def __init__(self, initialExpression=None): + "@sig public Graph(java.lang.String initialExpression)" + self.function = None + if initialExpression is not None: + self.setExpression(initialExpression) + + def paint(self, g): + if self.function is None: + return self.error(g) + + sz = self.size + xs = range(0, sz.width, 2) + + xscale = 4*pi/sz.width + xoffset = -2*pi + + yscale = -sz.height/2. + yoffset = sz.height/2. + + ys = [] + for x in xs: + x = xscale*x + xoffset + y = int(yscale*self.function(x)+yoffset) + ys.append(y) + g.drawPolyline(array(xs, 'i'), array(ys, 'i'), len(xs)) + + def error(self, g): + message = "Invalid Expression" + g.font = awt.Font('Serif', awt.Font.BOLD, 20) + width = g.fontMetrics.stringWidth(message) + + x = (self.size.width-width)/2 + y = (self.size.height+g.fontMetrics.height)/2 + g.drawString("Invalid Expression", x, y) + + def setExpression(self, e): + "@sig public void setExpression(java.lang.String e)" + try: + self.function = eval('lambda x: '+e) + except: + self.function = None + self.repaint() + if __name__ == '__main__': - def enter(e): - graph.setExpression(expression.text) - expression.caretPosition=0 - expression.selectAll() - - p = awt.Panel(layout=awt.BorderLayout()) - graph = Graph() - p.add(graph, 'Center') - - expression = awt.TextField(text='(sin(3*x)+cos(x))/2', actionPerformed=enter) - p.add(expression, 'South') - - import pawt - pawt.test(p, size=(300,300)) - - enter(None) + def enter(e): + graph.setExpression(expression.text) + expression.caretPosition = 0 + expression.selectAll() + + p = awt.Panel(layout=awt.BorderLayout()) + graph = Graph() + p.add(graph, 'Center') + + expression = awt.TextField( + text='(sin(3*x)+cos(x))/2', actionPerformed=enter) + p.add(expression, 'South') + + import pawt + pawt.test(p, size=(300, 300)) + + enter(None) diff --git a/Demo/modjy_webapp/demo_app.py b/Demo/modjy_webapp/demo_app.py index 39ddea33b..f88b53c8a 100644 --- a/Demo/modjy_webapp/demo_app.py +++ b/Demo/modjy_webapp/demo_app.py @@ -1,30 +1,37 @@ import sys -def escape_html(s): return s.replace('&', '&').replace('<', '<').replace('>', '>') + +def escape_html(s): return s.replace( + '&', '&').replace('<', '<').replace('>', '>') + def cutoff(s, n=100): - if len(s) > n: return s[:n]+ '.. cut ..' + if len(s) > n: + return s[:n] + '.. cut ..' return s + def handler(environ, start_response): - writer = start_response("200 OK", [ ('content-type', 'text/html') ]) + writer = start_response("200 OK", [('content-type', 'text/html')]) response_parts = [] response_parts.append("") response_parts.append("") response_parts.append("Modjy demo application") response_parts.append("") response_parts.append("") - response_parts.append("

Modjy servlet running correctly: jython %s on %s:

" % (sys.version, sys.platform)) + response_parts.append( + "

Modjy servlet running correctly: jython %s on %s:

" % (sys.version, sys.platform)) response_parts.append("

Hello WSGI World!

") - response_parts.append("

Here are the contents of the WSGI environment

") + response_parts.append( + "

Here are the contents of the WSGI environment

") environ_str = "" keys = environ.keys() keys.sort() for ix, name in enumerate(keys): if ix % 2: - background='#ffffff' + background = '#ffffff' else: - background='#eeeeee' + background = '#eeeeee' style = " style='background-color:%s;'" % background value = escape_html(cutoff(str(environ[name]))) or ' ' environ_str = "%s\n%s%s" % \ diff --git a/Demo/swing/JythonConsole/Action.py b/Demo/swing/JythonConsole/Action.py index e4e605049..ae988b02c 100644 --- a/Demo/swing/JythonConsole/Action.py +++ b/Demo/swing/JythonConsole/Action.py @@ -1,40 +1,43 @@ # I don't really like the design of this one... from pawt import swing + class Action(swing.AbstractAction): - def __init__(self, name, action=None, icon=None, description=None, needEvent=0): - if action is None: - action = name - name = action.__name__ - - #swing.AbstractAction.__init__(self, name) - self.name = name - self.icon = icon - if icon: - self.setIcon(swing.Action.SMALL_ICON, icon) - if description: - self.setText(swing.Action.SHORT_DESCRIPTION, description) - self.description = description - else: - self.description = name - self.action = action - - self.enabled = 1 - self.needEvent = needEvent - - def actionPerformed(self, event): - if self.needEvent: - self.action(event) - else: - self.action() - - def createMenuItem(self): - mi = swing.JMenuItem(self.name, actionListener=self, enabled=self.enabled) - return mi + def __init__(self, name, action=None, icon=None, description=None, needEvent=0): + if action is None: + action = name + name = action.__name__ + + #swing.AbstractAction.__init__(self, name) + self.name = name + self.icon = icon + if icon: + self.setIcon(swing.Action.SMALL_ICON, icon) + if description: + self.setText(swing.Action.SHORT_DESCRIPTION, description) + self.description = description + else: + self.description = name + self.action = action + + self.enabled = 1 + self.needEvent = needEvent + + def actionPerformed(self, event): + if self.needEvent: + self.action(event) + else: + self.action() + + def createMenuItem(self): + mi = swing.JMenuItem( + self.name, actionListener=self, enabled=self.enabled) + return mi + class TargetAction(Action): - def actionPerformed(self, event): - if self.needEvent: - self.action(self.getTarget(), event) - else: - self.action(self.getTarget()) \ No newline at end of file + def actionPerformed(self, event): + if self.needEvent: + self.action(self.getTarget(), event) + else: + self.action(self.getTarget()) diff --git a/Demo/swing/JythonConsole/Console.py b/Demo/swing/JythonConsole/Console.py index 2e510abee..57ec729ab 100644 --- a/Demo/swing/JythonConsole/Console.py +++ b/Demo/swing/JythonConsole/Console.py @@ -18,194 +18,204 @@ from java.awt.event import ActionEvent from java.lang import Thread, System from code import compile_command -import string, sys, re +import string +import sys +import re + class OutputBuffer: - def __init__(self, console, stylename): - self.console = console - self.stylename = stylename - - def flush(self): - pass - - def write(self, text): - self.console.write(text, self.stylename) + def __init__(self, console, stylename): + self.console = console + self.stylename = stylename + + def flush(self): + pass + + def write(self, text): + self.console.write(text, self.stylename) + class Console: - def __init__(self, styles=None, keymap=None): - if styles is None: - styles = Styles() - basic = styles.add('normal', tabsize=3, fontSize=12, fontFamily="Courier") - styles.add('error', parent=basic, foreground=colors.red) - styles.add('output', parent=basic, foreground=colors.blue) - styles.add('input', parent=basic, foreground=colors.black) - styles.add('prompt', parent=basic, foreground=colors.purple) - self.styles = styles - - # This is a hack to get at an inner class - # This will not be required in JPython-1.1 - ForegroundAction = getattr(swing.text, 'StyledEditorKit$ForegroundAction') - self.inputAction = ForegroundAction("start input", colors.black) - - if keymap is None: - keymap = Keymap() - keymap.bind('enter', self.enter) - keymap.bind('tab', self.tab) - keymap.bind('escape', self.escape) - keymap.bind('up', self.uphistory) - keymap.bind('down', self.downhistory) - - self.keymap = keymap - - self.document = swing.text.DefaultStyledDocument(self.styles) - self.document.setLogicalStyle(0, self.styles.get('normal')) - - self.textpane = swing.JTextPane(self.document) - self.textpane.keymap = self.keymap - - self.history = [] - self.oldHistoryLength = 0 - self.historyPosition = 0 - - self.command = [] - self.locals = {} - - def write(self, text, stylename='normal'): - style = self.styles.get(stylename) - self.document.insertString(self.document.length, text, style) - - def beep(self): - self.textpane.toolkit.beep() - - def startUserInput(self, prompt=None): - if prompt is not None: - self.write(prompt, 'prompt') - self.startInput = self.document.createPosition(self.document.length-1) - #self.document.setCharacterAttributes(self.document.length-1, 1, self.styles.get('input'), 1) - self.textpane.caretPosition = self.document.length - ae = ActionEvent(self.textpane, ActionEvent.ACTION_PERFORMED, 'start input') - self.inputAction.actionPerformed(ae) - - def getinput(self): - offset = self.startInput.offset - line = self.document.getText(offset+1, self.document.length-offset) - return string.rstrip(line) - - def replaceinput(self, text): - offset = self.startInput.offset + 1 - self.document.remove(offset, self.document.length-offset) - self.write(text, 'input') - - def enter(self): - line = self.getinput() - self.write('\n', 'input') - - self.history.append(line) - self.handleLine(line) - - def gethistory(self, direction): - historyLength = len(self.history) - if self.oldHistoryLength < historyLength: - # new line was entered after last call - self.oldHistoryLength = historyLength - if self.history[self.historyPosition] != self.history[-1]: - self.historyPosition = historyLength - - pos = self.historyPosition + direction - - if 0 <= pos < historyLength: - self.historyPosition = pos - self.replaceinput(self.history[pos]) - else: - self.beep() - - def uphistory(self): - self.gethistory(-1) - - def downhistory(self): - self.gethistory(1) - - def tab(self): - self.write('\t', 'input') - - def escape(self): - if (not hasattr(self, 'pythonThread') or self.pythonThread is None or - not self.pythonThread.alive): - self.beep() - return - - self.pythonThread.stopPython() - - def capturePythonOutput(self, stdoutStyle='output', stderrStyle='error'): - import sys - sys.stdout = OutputBuffer(self, stdoutStyle) - sys.stderr = OutputBuffer(self, stderrStyle) - - def handleLine(self, text): - self.command.append(text) - - try: - code = compile_command(string.join(self.command, '\n')) - except SyntaxError: - traceback.print_exc(0) - self.command = [] - self.startUserInput(str(sys.ps1)+'\t') - return - - if code is None: - self.startUserInput(str(sys.ps2)+'\t') - return - - self.command = [] - - pt = PythonThread(code, self) - self.pythonThread = pt - pt.start() - - def newInput(self): - self.startUserInput(str(sys.ps1)+'\t') - + def __init__(self, styles=None, keymap=None): + if styles is None: + styles = Styles() + basic = styles.add('normal', tabsize=3, + fontSize=12, fontFamily="Courier") + styles.add('error', parent=basic, foreground=colors.red) + styles.add('output', parent=basic, foreground=colors.blue) + styles.add('input', parent=basic, foreground=colors.black) + styles.add('prompt', parent=basic, foreground=colors.purple) + self.styles = styles + + # This is a hack to get at an inner class + # This will not be required in JPython-1.1 + ForegroundAction = getattr( + swing.text, 'StyledEditorKit$ForegroundAction') + self.inputAction = ForegroundAction("start input", colors.black) + + if keymap is None: + keymap = Keymap() + keymap.bind('enter', self.enter) + keymap.bind('tab', self.tab) + keymap.bind('escape', self.escape) + keymap.bind('up', self.uphistory) + keymap.bind('down', self.downhistory) + + self.keymap = keymap + + self.document = swing.text.DefaultStyledDocument(self.styles) + self.document.setLogicalStyle(0, self.styles.get('normal')) + + self.textpane = swing.JTextPane(self.document) + self.textpane.keymap = self.keymap + + self.history = [] + self.oldHistoryLength = 0 + self.historyPosition = 0 + + self.command = [] + self.locals = {} + + def write(self, text, stylename='normal'): + style = self.styles.get(stylename) + self.document.insertString(self.document.length, text, style) + + def beep(self): + self.textpane.toolkit.beep() + + def startUserInput(self, prompt=None): + if prompt is not None: + self.write(prompt, 'prompt') + self.startInput = self.document.createPosition(self.document.length-1) + #self.document.setCharacterAttributes(self.document.length-1, 1, self.styles.get('input'), 1) + self.textpane.caretPosition = self.document.length + ae = ActionEvent( + self.textpane, ActionEvent.ACTION_PERFORMED, 'start input') + self.inputAction.actionPerformed(ae) + + def getinput(self): + offset = self.startInput.offset + line = self.document.getText(offset+1, self.document.length-offset) + return string.rstrip(line) + + def replaceinput(self, text): + offset = self.startInput.offset + 1 + self.document.remove(offset, self.document.length-offset) + self.write(text, 'input') + + def enter(self): + line = self.getinput() + self.write('\n', 'input') + + self.history.append(line) + self.handleLine(line) + + def gethistory(self, direction): + historyLength = len(self.history) + if self.oldHistoryLength < historyLength: + # new line was entered after last call + self.oldHistoryLength = historyLength + if self.history[self.historyPosition] != self.history[-1]: + self.historyPosition = historyLength + + pos = self.historyPosition + direction + + if 0 <= pos < historyLength: + self.historyPosition = pos + self.replaceinput(self.history[pos]) + else: + self.beep() + + def uphistory(self): + self.gethistory(-1) + + def downhistory(self): + self.gethistory(1) + + def tab(self): + self.write('\t', 'input') + + def escape(self): + if (not hasattr(self, 'pythonThread') or self.pythonThread is None or + not self.pythonThread.alive): + self.beep() + return + + self.pythonThread.stopPython() + + def capturePythonOutput(self, stdoutStyle='output', stderrStyle='error'): + import sys + sys.stdout = OutputBuffer(self, stdoutStyle) + sys.stderr = OutputBuffer(self, stderrStyle) + + def handleLine(self, text): + self.command.append(text) + + try: + code = compile_command(string.join(self.command, '\n')) + except SyntaxError: + traceback.print_exc(0) + self.command = [] + self.startUserInput(str(sys.ps1)+'\t') + return + + if code is None: + self.startUserInput(str(sys.ps2)+'\t') + return + + self.command = [] + + pt = PythonThread(code, self) + self.pythonThread = pt + pt.start() + + def newInput(self): + self.startUserInput(str(sys.ps1)+'\t') + + import traceback + class PythonThread(Thread): - def __init__(self, code, console): - self.code = code - self.console = console - self.locals = console.locals - - def run(self): - try: - exec self.code in self.locals - - #Include these lines to actually exit on a sys.exit() call - #except SystemExit, value: - # raise SystemExit, value - - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - l = len(traceback.extract_tb(sys.exc_traceback)) - try: - 1/0 - except: - m = len(traceback.extract_tb(sys.exc_traceback)) - traceback.print_exception(exc_type, exc_value, exc_traceback, l-m) - - self.console.newInput() - - def stopPython(self): - #Should spend 2 seconds trying to kill thread in nice Python style first... - self.stop() + def __init__(self, code, console): + self.code = code + self.console = console + self.locals = console.locals + + def run(self): + try: + exec self.code in self.locals + + # Include these lines to actually exit on a sys.exit() call + # except SystemExit, value: + # raise SystemExit, value + + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + l = len(traceback.extract_tb(sys.exc_traceback)) + try: + 1/0 + except: + m = len(traceback.extract_tb(sys.exc_traceback)) + traceback.print_exception(exc_type, exc_value, exc_traceback, l-m) + + self.console.newInput() + + def stopPython(self): + # Should spend 2 seconds trying to kill thread in nice Python style first... + self.stop() + header = """\ JPython %(version)s on %(platform)s %(copyright)s -""" % {'version':sys.version, 'platform':sys.platform, 'copyright':sys.copyright} +""" % {'version': sys.version, 'platform': sys.platform, 'copyright': sys.copyright} if __name__ == '__main__': - c = Console() - pane = swing.JScrollPane(c.textpane) - swing.test(pane, size=(500,400), name='JPython Console') - c.write(header, 'output') - c.capturePythonOutput() - c.textpane.requestFocus() - c.newInput() \ No newline at end of file + c = Console() + pane = swing.JScrollPane(c.textpane) + swing.test(pane, size=(500, 400), name='JPython Console') + c.write(header, 'output') + c.capturePythonOutput() + c.textpane.requestFocus() + c.newInput() diff --git a/Demo/swing/JythonConsole/Keymap.py b/Demo/swing/JythonConsole/Keymap.py index 3e14cf980..cd91c9345 100644 --- a/Demo/swing/JythonConsole/Keymap.py +++ b/Demo/swing/JythonConsole/Keymap.py @@ -4,84 +4,93 @@ from Action import Action _keynames = {} + + def getKeyStroke(key): - if len(_keynames) == 0: - for name in dir(KeyEvent): - if name[:3] == 'VK_': - _keynames[string.lower(name[3:])] = getattr(KeyEvent, name) - - if key is None: - return KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED) - - if len(key) == 1: - return KeyStroke.getKeyStroke(key) - - fields = string.split(key, '-') - key = fields[-1] - mods = fields[:-1] - - modifiers = 0 - for mod in mods: - if mod == 'C': - modifiers = modifiers | InputEvent.CTRL_MASK - elif mod == 'S': - modifiers = modifiers | InputEvent.SHIFT_MASK - #Meta and Alt don't currently work right - elif mod == 'M': - modifiers = modifiers | InputEvent.META_MASK - elif mod == 'A': - modifiers = modifiers | InputEvent.ALT_MASK - else: - raise ValueError, 'Invalid modifier in '+key - - return KeyStroke.getKeyStroke(_keynames[key], modifiers) + if len(_keynames) == 0: + for name in dir(KeyEvent): + if name[:3] == 'VK_': + _keynames[string.lower(name[3:])] = getattr(KeyEvent, name) + + if key is None: + return KeyStroke.getKeyStroke(KeyEvent.CHAR_UNDEFINED) + + if len(key) == 1: + return KeyStroke.getKeyStroke(key) + + fields = string.split(key, '-') + key = fields[-1] + mods = fields[:-1] + + modifiers = 0 + for mod in mods: + if mod == 'C': + modifiers = modifiers | InputEvent.CTRL_MASK + elif mod == 'S': + modifiers = modifiers | InputEvent.SHIFT_MASK + # Meta and Alt don't currently work right + elif mod == 'M': + modifiers = modifiers | InputEvent.META_MASK + elif mod == 'A': + modifiers = modifiers | InputEvent.ALT_MASK + else: + raise ValueError, 'Invalid modifier in '+key + + return KeyStroke.getKeyStroke(_keynames[key], modifiers) def makeAction(o): - if isinstance(o, Action): return o - if callable(o): return Action(o) + if isinstance(o, Action): + return o + if callable(o): + return Action(o) + class Keymap: - __keynames = {} - __defaultKeymap = text.JTextComponent.getKeymap(text.JTextComponent.DEFAULT_KEYMAP) + __keynames = {} + __defaultKeymap = text.JTextComponent.getKeymap( + text.JTextComponent.DEFAULT_KEYMAP) - def __init__(self, bindings={}, parent=__defaultKeymap): - self.keymap = text.JTextComponent.addKeymap(None, parent) - for key, action in bindings.items(): - self.bind(key, action) + def __init__(self, bindings={}, parent=__defaultKeymap): + self.keymap = text.JTextComponent.addKeymap(None, parent) + for key, action in bindings.items(): + self.bind(key, action) - def bind(self, key, action): - self.keymap.addActionForKeyStroke(getKeyStroke(key), makeAction(action)) + def bind(self, key, action): + self.keymap.addActionForKeyStroke( + getKeyStroke(key), makeAction(action)) + + def __tojava__(self, c): + if isinstance(self.keymap, c): + return self.keymap - def __tojava__(self, c): - if isinstance(self.keymap, c): - return self.keymap if __name__ == '__main__': - km = Keymap() - class T: - def __init__(self, message): - self.message = message - self.__name__ = message - def __call__(self): - print self.message + km = Keymap() + + class T: + def __init__(self, message): + self.message = message + self.__name__ = message - km.bind('x', T('x')) - km.bind('C-x', T('C-x')) - km.bind('A-x', T('A-x')) - km.bind('up', T('up')) - km.bind('enter', T('enter')) - km.bind('tab', T('tab')) - km.bind('S-tab', T('S-tab')) + def __call__(self): + print self.message + km.bind('x', T('x')) + km.bind('C-x', T('C-x')) + km.bind('A-x', T('A-x')) + km.bind('up', T('up')) + km.bind('enter', T('enter')) + km.bind('tab', T('tab')) + km.bind('S-tab', T('S-tab')) - text = "hello\nworld" + text = "hello\nworld" - from pawt import swing, test + from pawt import swing, test - doc = swing.text.DefaultStyledDocument() - doc.insertString(0, text, None) - edit = swing.JTextPane(doc) - edit.keymap = km + doc = swing.text.DefaultStyledDocument() + doc.insertString(0, text, None) + edit = swing.JTextPane(doc) + edit.keymap = km - test(edit, size=(150,80)) + test(edit, size=(150, 80)) diff --git a/Demo/swing/JythonConsole/Styles.py b/Demo/swing/JythonConsole/Styles.py index a90f30b80..767e843df 100644 --- a/Demo/swing/JythonConsole/Styles.py +++ b/Demo/swing/JythonConsole/Styles.py @@ -1,34 +1,35 @@ from pawt.swing.text import StyleContext, StyleConstants, TabSet, TabStop import string + class Styles: - def __init__(self, context=None): - if context is None: - context = StyleContext() - self.context = context - self.default = self.context.getStyle(StyleContext.DEFAULT_STYLE) + def __init__(self, context=None): + if context is None: + context = StyleContext() + self.context = context + self.default = self.context.getStyle(StyleContext.DEFAULT_STYLE) - def add(self, name, parent=None, tabsize=None, **keywords): - if parent is None: - parent = self.default - style = self.context.addStyle(name, parent) + def add(self, name, parent=None, tabsize=None, **keywords): + if parent is None: + parent = self.default + style = self.context.addStyle(name, parent) - for key, value in keywords.items(): - key = string.upper(key[0])+key[1:] - meth = getattr(StyleConstants, "set"+key) - meth(style, value) + for key, value in keywords.items(): + key = string.upper(key[0])+key[1:] + meth = getattr(StyleConstants, "set"+key) + meth(style, value) - if tabsize is not None: - charWidth=StyleConstants.getFontSize(style) - tabs = [] - for i in range(20): - tabs.append(TabStop(i*tabsize*charWidth)) - StyleConstants.setTabSet(style, TabSet(tabs)) - return style + if tabsize is not None: + charWidth = StyleConstants.getFontSize(style) + tabs = [] + for i in range(20): + tabs.append(TabStop(i*tabsize*charWidth)) + StyleConstants.setTabSet(style, TabSet(tabs)) + return style - def get(self, stylename): - return self.context.getStyle(stylename) + def get(self, stylename): + return self.context.getStyle(stylename) - def __tojava__(self, c): - if isinstance(self.context, c): - return self.context \ No newline at end of file + def __tojava__(self, c): + if isinstance(self.context, c): + return self.context diff --git a/Demo/swing/ListDemo.py b/Demo/swing/ListDemo.py index d8b8f4b58..5b6d52b59 100644 --- a/Demo/swing/ListDemo.py +++ b/Demo/swing/ListDemo.py @@ -3,4 +3,3 @@ lst = swing.JList(['a', 'b', 'c']) swing.test(lst) - diff --git a/Demo/swing/ObjectTree.py b/Demo/swing/ObjectTree.py index 280e0432a..8652e88e1 100644 --- a/Demo/swing/ObjectTree.py +++ b/Demo/swing/ObjectTree.py @@ -9,8 +9,7 @@ import java leaves = (None, TypeType, IntType, StringType, FloatType, NoneType, - BuiltinFunctionType, BuiltinMethodType) - + BuiltinFunctionType, BuiltinMethodType) class PyEnumeration(java.util.Enumeration): @@ -26,13 +25,13 @@ def nextElement(self): return self.seq[self.index-1] - def classattrs(c, attrs): for base in c.__bases__: classattrs(base, attrs) for name in c.__dict__.keys(): attrs[name] = 1 + def mydir(obj): attrs = {} if hasattr(obj, '__class__'): @@ -44,6 +43,7 @@ def mydir(obj): ret.sort() return ret + def shortrepr(obj): r = repr(obj) if len(r) > 80: @@ -51,7 +51,6 @@ def shortrepr(obj): return r - class ObjectNode(swing.tree.TreeNode): def __init__(self, parent, name, object): self.myparent = parent @@ -60,7 +59,7 @@ def __init__(self, parent, name, object): def getChildren(self): if hasattr(self, 'mychildren'): - return self.mychildren + return self.mychildren if self.isLeaf(): self.mychildren = None @@ -69,10 +68,10 @@ def getChildren(self): children = [] for name in mydir(self.object): if name[:2] == '__': - continue + continue try: children.append(ObjectNode(self, name, - getattr(self.object, name))) + getattr(self.object, name))) except TypeError: print 'type error on', name, self.object self.mychildren = children @@ -102,7 +101,7 @@ def getIndex(self, node): index = 0 for child in self.getChildren(): if child == node: - return index + return index index = index+1 return -1 @@ -113,13 +112,13 @@ def toString(self): return self.name+' = '+shortrepr(self.object) - if __name__ == '__main__': class foo: - bar=99 - eggs='hello' + bar = 99 + eggs = 'hello' + class baz: - x,y,z=1,2,3 + x, y, z = 1, 2, 3 func = range import __main__ diff --git a/Demo/swing/TreeDemo.py b/Demo/swing/TreeDemo.py index fd24302be..e74675296 100644 --- a/Demo/swing/TreeDemo.py +++ b/Demo/swing/TreeDemo.py @@ -4,47 +4,51 @@ """ data = { - 'PyObject': { - 'PyInteger':None, - 'PyFloat':None, - 'PyComplex':None, + 'PyObject': { + 'PyInteger': None, + 'PyFloat': None, + 'PyComplex': None, 'PySequence': { - 'PyArray':None, - 'PyList':None, - 'PyTuple':None, - 'PyString':None, + 'PyArray': None, + 'PyList': None, + 'PyTuple': None, + 'PyString': None, }, 'PyClass': { - 'PyJavaClass':None, + 'PyJavaClass': None, }, - }, - 'sys':None, - 'Py':None, - 'PyException':None, - '__builtin__':None, - 'ThreadState':None, + }, + 'sys': None, + 'Py': None, + 'PyException': None, + '__builtin__': None, + 'ThreadState': None, } from pawt import swing Node = swing.tree.DefaultMutableTreeNode + def addNode(tree, key, value): - node = Node(key) - tree.add(node) - if value is not None: - addLeaves(node, value.items()) + node = Node(key) + tree.add(node) + if value is not None: + addLeaves(node, value.items()) + def addLeaves(node, items): - items.sort() - for key, value in items: - addNode(node, key, value) + items.sort() + for key, value in items: + addNode(node, key, value) + def makeTree(name, data): - tree = Node('A Few JPython Classes') - addLeaves(tree, data.items()) - return tree + tree = Node('A Few JPython Classes') + addLeaves(tree, data.items()) + return tree + if __name__ == '__main__': - tree = makeTree('Some JPython Classes', data) - swing.test(swing.JScrollPane(swing.JTree(tree))) + tree = makeTree('Some JPython Classes', data) + swing.test(swing.JScrollPane(swing.JTree(tree))) diff --git a/Demo/swing/simple.py b/Demo/swing/simple.py index 787c0c298..a4bf56c7b 100644 --- a/Demo/swing/simple.py +++ b/Demo/swing/simple.py @@ -7,8 +7,10 @@ from pawt import swing import java + def exit(e): java.lang.System.exit(0) + frame = swing.JFrame('Swing Example', visible=1) button = swing.JButton('Close Me!', actionPerformed=exit) frame.contentPane.add(button) diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..e7a49fce0 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,73 @@ +#!/usr/bin/env groovy + +@Library('ds-pipeline-lib') + +import java.security.MessageDigest +def id = MessageDigest.getInstance("MD5").digest(System.currentTimeMillis().toString().bytes).encodeHex().toString().substring(0,8) + +// Build Jython forked repository and push artifacts to artifactory + +pipeline { + agent { + node { + label 'default-runner' + customWorkspace "workspace/${BUILD_NUMBER}-package-build-${id}" + } + } + + tools { + jdk('jdk-8') + } + + parameters { + string(name: 'buildbranch', defaultValue: 'OPSC-16690', description: 'The branch to build. Only valid for the branch build job.') + } + + options { + disableConcurrentBuilds() + buildDiscarder(logRotator(numToKeepStr: '30')) + timeout(time: 120, unit: 'MINUTES') + timestamps() + } + + stages { + stage('Build') { + steps { + configFileProvider([configFile(fileId: 'gradle.properties', + replaceTokens: true, + targetLocation: 'gradle.properties')]) { + withAnt(installation: 'ant-1.10.7') { + sh "ant installer" + sh "mkdir artifacts" + sh "cp dist/jython-standalone* artifacts/" + sh "cp dist/jython-installer* artifacts/" + } + } + archiveArtifacts artifacts: 'dist/jython-standalone-*.jar', onlyIfSuccessful: true, defaultExcludes: false, caseSensitive: false + archiveArtifacts artifacts: 'dist/jython-installer-*.jar', onlyIfSuccessful: true, defaultExcludes: false, caseSensitive: false + } + } + stage ('Upload to artifactory') { + steps { + script { + def directoryPath = 'artifacts' + def filenames = sh(script: "ls ${directoryPath}", returnStdout: true).trim().split('\n') + + withCredentials([usernamePassword(credentialsId: 'dse-artifactory', + usernameVariable: 'ARTIFACTORY_USER', + passwordVariable: 'ARTIFACTORY_PASSWORD')]) { + for (def filename in filenames) { + sh "echo $filename" + sh "curl -sSf -u '$ARTIFACTORY_USER:$ARTIFACTORY_PASSWORD' -X PUT -T artifacts/$filename 'https://repo.aws.dsinternal.org/artifactory/datastax-public-releases-local/com/datastax/opscenter/jython-standalone/2.7.3a1/$filename'" + } + } + } + } + } + stage('wrapup') { + steps { + cleanWs notFailBuild: true + } + } + } +} diff --git a/LICENSE.txt b/LICENSE.txt index 205e8649a..1ff74bea4 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -188,13 +188,15 @@ From the 2.2 release on, Jython contributors have signed Python Software Foundation contributor agreements and releases are covered under the Python Software Foundation license version 2. -The standard library is covered by the Python Software Foundation -license as well. See the Lib/LICENSE file for details. +The Python standard library developed for CPython is also used in Jython, and +(like Jython itself) is provided under the Python Software Foundation +license. See the file LICENSE_CPython.txt for details. The zxJDBC package was written by Brian Zimmer and originally licensed under the GNU Public License. The package is now covered by the Jython Software License. -The command line interpreter is covered by the Apache Software -License. See the org/apache/LICENSE file for details. +Elements of the supporting libraries (appearing renamed in some Jython JARs) +are covered by the Apache Software License. See the file LICENSE_Apache.txt +for details. diff --git a/Lib/_fix_jython_setuptools_osx.py b/Lib/_fix_jython_setuptools_osx.py new file mode 100644 index 000000000..ef1d7ef19 --- /dev/null +++ b/Lib/_fix_jython_setuptools_osx.py @@ -0,0 +1,33 @@ +''' +Import of this module is triggered by org.python.core.imp.import_next +on first import of setuptools.command. It essentially restores a +Jython specific fix for OSX shebang line via monkeypatching. + +See http://bugs.jython.org/issue2570 +Related: http://bugs.jython.org/issue1112 +''' + +from setuptools.command import easy_install as ez + +_as_header = ez.CommandSpec.as_header + +def _jython_as_header(self): + '''Workaround Jython's sys.executable being a .sh (an invalid + shebang line interpreter) + ''' + if not ez.is_sh(self[0]): + return _as_header(self) + + if self.options: + # Can't apply the workaround, leave it broken + log.warn( + "WARNING: Unable to adapt shebang line for Jython," + " the following script is NOT executable\n" + " see http://bugs.jython.org/issue1112 for" + " more information.") + return _as_header(self) + + items = ['/usr/bin/env'] + self + list(self.options) + return self._render(items) + +ez.CommandSpec.as_header = _jython_as_header diff --git a/Lib/_socket.py b/Lib/_socket.py index 791853f57..398d2e1df 100644 --- a/Lib/_socket.py +++ b/Lib/_socket.py @@ -350,7 +350,17 @@ def _map_exception(java_exception): msg = java_exception.message py_exception = SSLError(SSL_ERROR_SSL, msg) else: - mapped_exception = _exception_map.get(java_exception.__class__) + # Netty 4.1.6 or higher wraps the connection exception in a + # private static class that inherits from ConnectException, so + # need to work around. + if isinstance(java_exception, java.net.ConnectException): + mapped_exception = _exception_map.get(java.net.ConnectException) + # Netty AnnotatedNoRouteToHostException extends NoRouteToHostException + # so also needs work around. + elif isinstance(java_exception, java.net.NoRouteToHostException): + mapped_exception = _exception_map.get(java.net.NoRouteToHostException) + else: + mapped_exception = _exception_map.get(java_exception.__class__) if mapped_exception: py_exception = mapped_exception(java_exception) else: @@ -381,6 +391,22 @@ def handle_exception(*args, **kwargs): args[0]._last_error = 0 return handle_exception +def _fsencode(name): + """Ensure that a name that may be given as a unicode object (e.g. returned + from Java) is converted to the expected bytes representation using the + file-system encoding.""" + if isinstance(name, unicode): + return name.encode(sys.getfilesystemencoding()) + return name + +def _fsdecode(name): + """Ensure that a name that may be given as a bytes object (normal for + Python) is converted to the Unicode representation (e.g for Java) using the + file-system encoding.""" + if isinstance(name, bytes): + return unicode(name, sys.getfilesystemencoding()) + return name + # select support ################ @@ -797,13 +823,13 @@ def _notify_selectors(self, exception=None, hangup=False): selector.notify(self, exception=exception, hangup=hangup) @raises_java_exception - def _handle_channel_future(self, future, reason): + def _handle_channel_future(self, future, reason, wait=False): # All differences between nonblocking vs blocking with optional timeouts # is managed by this method. # # All sockets can be selected on, regardless of blocking/nonblocking state. future.addListener(self._notify_selectors) - if self.timeout is None: + if self.timeout is None or wait: log.debug("Syncing on future %s for %s", future, reason, extra={"sock": self}) return future.sync() elif self.timeout: @@ -1183,6 +1209,7 @@ def send(self, data, flags=0): bytes_writable = self.channel.bytesBeforeUnwritable() if bytes_writable > len(data): bytes_writable = len(data) + bytes_writable = min(bytes_writable, 8192) sent_data = data[:bytes_writable] @@ -1754,7 +1781,12 @@ def getaddrinfo(host, port, family=AF_UNSPEC, socktype=0, proto=0, flags=0): hosts = [host] results = [] for h in hosts: - for a in java.net.InetAddress.getAllByName(h): + try: + all_by_name = java.net.InetAddress.getAllByName(h) + except java.net.UnknownHostException: + raise gaierror(errno.ENOEXEC, 'nodename nor servname provided, or not known') + + for a in all_by_name: if len([f for f in filter_fns if f(a)]): family = {java.net.Inet4Address: AF_INET, java.net.Inet6Address: AF_INET6}[a.getClass()] if flags & AI_CANONNAME: @@ -1857,11 +1889,13 @@ def getfqdn(name=None): @raises_java_exception def gethostname(): - return str(InetAddress.getLocalHost().getHostName()) + """Return FS-encoded local host name.""" + return _fsencode(InetAddress.getLocalHost().getHostName()) @raises_java_exception def gethostbyname(name): - return str(InetAddress.getByName(name).getHostAddress()) + """Return IP address as string from FS-decoded host name.""" + return str(InetAddress.getByName(_fsdecode(name)).getHostAddress()) # # Skeleton implementation of gethostbyname_ex @@ -2031,7 +2065,7 @@ def fileno(self): return self._sock.fileno() def write(self, data): - data = str(data) # XXX Should really reject non-string non-buffers + data = str(data) # XXX Should really reject non-byte non-buffers if not data: return self._wbuf.append(data) diff --git a/Lib/_sslcerts.py b/Lib/_sslcerts.py index 3902a035d..adf867561 100644 --- a/Lib/_sslcerts.py +++ b/Lib/_sslcerts.py @@ -10,8 +10,15 @@ from java.security.cert import CertificateException, CertificateFactory from java.security.interfaces import RSAPrivateCrtKey from java.security.interfaces import RSAPublicKey -from javax.net.ssl import ( - X509KeyManager, X509TrustManager, KeyManagerFactory, SSLContext, TrustManager, TrustManagerFactory) +from javax.net.ssl import X509KeyManager, X509TrustManager, KeyManagerFactory, SSLContext + +try: + # jarjar-ed version + from org.python.netty.handler.ssl.util import SimpleTrustManagerFactory + +except ImportError: + # dev version from extlibs + from io.netty.handler.ssl.util import SimpleTrustManagerFactory try: # dev version from extlibs OR if in classpath. @@ -33,9 +40,10 @@ from org.bouncycastle.jce.provider import BouncyCastleProvider from org.bouncycastle.jce import ECNamedCurveTable from org.bouncycastle.jce.spec import ECNamedCurveSpec - from org.bouncycastle.openssl import PEMKeyPair, PEMParser, PEMEncryptedKeyPair, PEMException, \ - EncryptionException + from org.bouncycastle.openssl import PEMKeyPair, PEMParser, PEMEncryptedKeyPair, \ + PEMException, EncryptionException from org.bouncycastle.openssl.jcajce import JcaPEMKeyConverter, JcePEMDecryptorProviderBuilder + from org.bouncycastle.util.encoders import DecoderException except ImportError: # jarjar-ed version from org.python.bouncycastle.asn1.pkcs import PrivateKeyInfo @@ -44,9 +52,10 @@ from org.python.bouncycastle.jce.provider import BouncyCastleProvider from org.python.bouncycastle.jce import ECNamedCurveTable from org.python.bouncycastle.jce.spec import ECNamedCurveSpec - from org.python.bouncycastle.openssl import PEMKeyPair, PEMParser, PEMEncryptedKeyPair, PEMException, \ - EncryptionException + from org.python.bouncycastle.openssl import PEMKeyPair, PEMParser, PEMEncryptedKeyPair, \ + PEMException, EncryptionException from org.python.bouncycastle.openssl.jcajce import JcaPEMKeyConverter, JcePEMDecryptorProviderBuilder + from org.python.bouncycastle.util.encoders import DecoderException log = logging.getLogger("_socket") Security.addProvider(BouncyCastleProvider()) @@ -64,7 +73,7 @@ def _get_ca_certs_trust_manager(ca_certs=None): for cert in cf.generateCertificates(BufferedInputStream(f)): trust_store.setCertificateEntry(str(uuid.uuid4()), cert) num_certs_installed += 1 - tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) + tmf = SimpleTrustManagerFactory.getInstance(SimpleTrustManagerFactory.getDefaultAlgorithm()) tmf.init(trust_store) log.debug("Installed %s certificates", num_certs_installed, extra={"sock": "*"}) return tmf @@ -236,6 +245,11 @@ def _extract_cert_from_data(f, password=None, key_converter=None, cert_converter def _read_pem_cert_from_data(f, password, key_converter, cert_converter): + + def PEM_SSLError(err): # Shorthand + from _socket import SSLError, SSL_ERROR_SSL + return SSLError(SSL_ERROR_SSL, "PEM lib ({})".format(err)) + certs = [] private_key = None @@ -248,8 +262,9 @@ def _read_pem_cert_from_data(f, password, key_converter, cert_converter): try: obj = PEMParser(br).readObject() except PEMException as err: - from _socket import SSLError, SSL_ERROR_SSL - raise SSLError(SSL_ERROR_SSL, "PEM lib ({})".format(err)) + raise PEM_SSLError(err) + except DecoderException as err: + raise PEM_SSLError(err) if obj is None: break @@ -265,8 +280,7 @@ def _read_pem_cert_from_data(f, password, key_converter, cert_converter): try: key_pair = key_converter.getKeyPair(obj.decryptKeyPair(provider)) except EncryptionException as err: - from _socket import SSLError, SSL_ERROR_SSL - raise SSLError(SSL_ERROR_SSL, "PEM lib ({})".format(err)) + raise PEM_SSLError(err) private_key = key_pair.getPrivate() else: @@ -329,7 +343,7 @@ def chooseServerAlias(self, key_type, issuers, socket): def getPrivateKey(self, alias): for key_manager in self.key_managers: - private_key = keyManager.getPrivateKey(alias) + private_key = key_manager.getPrivateKey(alias) if private_key: return private_key return None @@ -404,14 +418,13 @@ def getAcceptedIssuers(self): return certs -# To use with CERT_NONE -class NoVerifyX509TrustManager(X509TrustManager): +class CompositeX509TrustManagerFactory(SimpleTrustManagerFactory): - def checkClientTrusted(self, chain, auth_type): - pass + def __init__(self, trust_managers): + self._trust_manager = CompositeX509TrustManager(trust_managers) - def checkServerTrusted(self, chain, auth_type): + def engineInit(self, arg): pass - def getAcceptedIssuers(self): - return None + def engineGetTrustManagers(self): + return [self._trust_manager] diff --git a/Lib/compileall.py b/Lib/compileall.py index 6b894e067..be803d586 100644 --- a/Lib/compileall.py +++ b/Lib/compileall.py @@ -86,7 +86,7 @@ def compile_file(fullname, ddir=None, force=0, rx=None, quiet=0): try: mtime = int(os.stat(fullname).st_mtime) expect = struct.pack('<4sl', imp.get_magic(), mtime) - cfile = fullname.replace('.py', '$py.class') + cfile = imp._makeCompiledFilename(fullname) with open(cfile, 'rb') as chandle: actual = chandle.read(8) if expect == actual: diff --git a/Lib/datetime.py b/Lib/datetime.py index 6d87773e9..b97e9cf5c 100644 --- a/Lib/datetime.py +++ b/Lib/datetime.py @@ -43,6 +43,9 @@ def _make_java_utc_calendar(): cal.clear() return cal + def _make_java_default_calendar(): + return GregorianCalendar(0, 0, 0, 0, 0, 0) + def _make_java_calendar(d): tzinfo = d.tzinfo if tzinfo == None: @@ -1073,11 +1076,13 @@ def __reduce__(self): def __tojava__(self, java_class): if java_class not in (Calendar, Date, Object): return Py.NoConversion - calendar = _make_java_utc_calendar() - calendar.set(self.year, self.month - 1, self.day) if java_class == Calendar: + calendar = _make_java_utc_calendar() + calendar.set(self.year, self.month - 1, self.day) return calendar else: + calendar = _make_java_default_calendar() + calendar.set(self.year, self.month - 1, self.day) return Date(calendar.getTimeInMillis()) @@ -1493,8 +1498,16 @@ def __tojava__(self, java_class): calendar = _make_java_calendar(self) if calendar == Py.NoConversion: return Py.NoConversion - epoch_ms = (self.hour * 3600 + self.minute * 60 + self.second) * 1000 + self.microsecond // 1000 - calendar.setTimeInMillis(epoch_ms) + + #initialize to epoch time - effectively clear out the current date from the calendar. + calendar.setTimeInMillis(0); + + #now setup the calendar to have the details populated from this time. + calendar.set(Calendar.HOUR_OF_DAY, self.hour) + calendar.set(Calendar.MINUTE, self.minute) + calendar.set(Calendar.SECOND, self.second) + calendar.set(Calendar.MILLISECOND, self.microsecond // 1000) + if java_class == Calendar: return calendar else: diff --git a/Lib/distutils/jythoncompiler.py b/Lib/distutils/jythoncompiler.py index 91d106a4b..7a5af3ff6 100644 --- a/Lib/distutils/jythoncompiler.py +++ b/Lib/distutils/jythoncompiler.py @@ -5,7 +5,7 @@ """ from distutils.ccompiler import CCompiler -from distutils.errors import CCompilerError +import warnings class JythonCompiler(CCompiler): @@ -16,6 +16,7 @@ class JythonCompiler(CCompiler): def refuse_compilation(self, *args, **kwargs): """Refuse compilation""" - raise CCompilerError('Compiling extensions is not supported on Jython') + warnings.warn('Compiling extensions is not supported on Jython') + return [] preprocess = compile = create_static_lib = link = refuse_compilation diff --git a/Lib/distutils/spawn.py b/Lib/distutils/spawn.py index e32005204..3a24bd811 100644 --- a/Lib/distutils/spawn.py +++ b/Lib/distutils/spawn.py @@ -235,8 +235,10 @@ def find_executable(executable, path=None): paths = path.split(os.pathsep) base, ext = os.path.splitext(executable) - if (sys.platform == 'win32' or os.name == 'os2') and (ext != '.exe'): - executable = executable + '.exe' + if (sys.platform == 'win32' or os.name == 'os2' or + sys.platform.startswith('java') and os._name == 'nt'): + if ext != '.exe': + executable = executable + '.exe' if not os.path.isfile(executable): for p in paths: diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index 570da7371..d45cab5d6 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -12,6 +12,8 @@ from distutils.spawn import spawn from distutils import log from distutils.errors import DistutilsByteCompileError +if sys.platform.startswith('java'): + import _imp def get_platform (): """Return a string that identifies the current platform. This is used @@ -534,7 +536,7 @@ def byte_compile (py_files, # mode simply calls 'byte_compile()' in direct mode, a weird sort of # cross-process recursion. Hey, it works! else: - from py_compile import compile + import py_compile for file in py_files: if file[-3:] != ".py": @@ -546,7 +548,7 @@ def byte_compile (py_files, # cfile - byte-compiled file # dfile - purported source filename (same as 'file' by default) if sys.platform.startswith('java'): - cfile = file[:-3] + '$py.class' + cfile = _imp.makeCompiledFilename(file) else: cfile = file + (__debug__ and "c" or "o") dfile = file @@ -564,7 +566,7 @@ def byte_compile (py_files, if force or newer(file, cfile): log.info("byte-compiling %s to %s", file, cfile_base) if not dry_run: - compile(file, cfile, dfile) + py_compile.compile(file, cfile, dfile) else: log.debug("skipping byte-compilation of %s to %s", file, cfile_base) diff --git a/Lib/encodings/_java.py b/Lib/encodings/_java.py index f7b9094fd..c149916ac 100644 --- a/Lib/encodings/_java.py +++ b/Lib/encodings/_java.py @@ -162,12 +162,16 @@ def decode(self, input, final=False): def reset(self): self.buffer = "" + self.decoder.reset() def getstate(self): - return self.buffer or 0 + # No way to extract the internal state of a Java decoder. + return self.buffer or "", 0 def setstate(self, state): - self.buffer = state or "" + self.buffer, _ = state or ("", 0) + # No way to restore: reset possible EOF state. + self.decoder.reset() class StreamWriter(NonfinalCodec, codecs.StreamWriter): diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py index a1f66e6a5..b2f5f8808 100644 --- a/Lib/ensurepip/__init__.py +++ b/Lib/ensurepip/__init__.py @@ -12,9 +12,9 @@ __all__ = ["version", "bootstrap"] -_SETUPTOOLS_VERSION = "19.2" +_SETUPTOOLS_VERSION = "41.0.1" -_PIP_VERSION = "7.1.2" +_PIP_VERSION = "19.1" # pip currently requires ssl support, so we try to provide a nicer # error message when that is missing (http://bugs.python.org/issue19744) @@ -42,8 +42,8 @@ def _run_pip(args, additional_paths=None): sys.path = additional_paths + sys.path # Install the bundled software - import pip - pip.main(args) + from pip._internal import main + main(args) def version(): diff --git a/Lib/ensurepip/_bundled/pip-19.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-19.1-py2.py3-none-any.whl new file mode 100644 index 000000000..2d3ac5d98 Binary files /dev/null and b/Lib/ensurepip/_bundled/pip-19.1-py2.py3-none-any.whl differ diff --git a/Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl deleted file mode 100644 index 519958a9e..000000000 Binary files a/Lib/ensurepip/_bundled/pip-7.1.2-py2.py3-none-any.whl and /dev/null differ diff --git a/Lib/ensurepip/_bundled/setuptools-19.2-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-19.2-py2.py3-none-any.whl deleted file mode 100644 index e57e87e8b..000000000 Binary files a/Lib/ensurepip/_bundled/setuptools-19.2-py2.py3-none-any.whl and /dev/null differ diff --git a/Lib/ensurepip/_bundled/setuptools-41.0.1-py2.py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-41.0.1-py2.py3-none-any.whl new file mode 100644 index 000000000..92836e984 Binary files /dev/null and b/Lib/ensurepip/_bundled/setuptools-41.0.1-py2.py3-none-any.whl differ diff --git a/Lib/imp.py b/Lib/imp.py index eae26d4fe..ddc389d86 100644 --- a/Lib/imp.py +++ b/Lib/imp.py @@ -4,7 +4,8 @@ __doc__, acquire_lock, find_module, getClass, get_magic, get_suffixes, is_builtin, is_frozen, load_compiled, load_dynamic, load_module, load_source, - lock_held, new_module, release_lock, reload) + lock_held, new_module, release_lock, reload, + makeCompiledFilename as _makeCompiledFilename) class NullImporter(object): @@ -15,4 +16,3 @@ def __init__(self, path): def find_module(self, fullname, path=None): return None - diff --git a/Lib/javashell.py b/Lib/javashell.py index 261e433fa..8910000c0 100755 --- a/Lib/javashell.py +++ b/Lib/javashell.py @@ -55,7 +55,7 @@ def execute( self, cmd ): env = self._formatEnvironment( self.environment ) try: - p = Runtime.getRuntime().exec( shellCmd, env, File(os.getcwd()) ) + p = Runtime.getRuntime().exec( shellCmd, env, File(os.getcwdu()) ) return p except IOException, ex: raise OSError( diff --git a/Lib/json/tests/test_dunderdict.py b/Lib/json/tests/test_dunderdict.py new file mode 100644 index 000000000..8a06861af --- /dev/null +++ b/Lib/json/tests/test_dunderdict.py @@ -0,0 +1,37 @@ +from cStringIO import StringIO +from json.tests import PyTest, CTest + + +class WrapDict(object): + + def __init__(self, d): + # Force a copy of the items in d, otherwise __dict__ will be a + # PyDictionary, instead of the desired PyStringMap for this + # testing + self.__dict__.update(d) + + +class TestDunderDictDump(object): + + def use_dunderdict(self, d): + return WrapDict(d).__dict__ + + def test_dump(self): + sio = StringIO() + self.json.dump(self.use_dunderdict({}), sio) + self.assertEqual(sio.getvalue(), '{}') + + def test_dumps(self): + self.assertEqual(self.dumps(self.use_dunderdict({})), '{}') + + def test_encode_truefalse(self): + self.assertEqual(self.dumps( + self.use_dunderdict({True: False, False: True}), sort_keys=True), + '{"false": true, "true": false}') + self.assertEqual(self.dumps( + self.use_dunderdict({2: 3.0, 4.0: 5L, False: 1, 6L: True}), sort_keys=True), + '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + + +class TestPyDump(TestDunderDictDump, PyTest): pass +class TestCDump(TestDunderDictDump, CTest): pass diff --git a/Lib/json/tests/test_recursion.py b/Lib/json/tests/test_recursion.py index 8ed3fc62f..4ebb10092 100644 --- a/Lib/json/tests/test_recursion.py +++ b/Lib/json/tests/test_recursion.py @@ -1,4 +1,6 @@ from json.tests import PyTest, CTest +import unittest +from test import test_support class JSONTestObject: @@ -65,6 +67,7 @@ def default(self, o): self.fail("didn't raise ValueError on default recursion") + @unittest.skipIf(test_support.is_jython, "See http://bugs.jython.org/issue2536.") def test_highly_nested_objects_decoding(self): # test that loading highly-nested objects doesn't segfault when C # accelerations are used. See #12017 @@ -83,6 +86,7 @@ def test_highly_nested_objects_decoding(self): with self.assertRaises(RuntimeError): self.loads(u'[' * 100000 + u'1' + u']' * 100000) + @unittest.skipIf(test_support.is_jython, "See http://bugs.jython.org/issue2536.") def test_highly_nested_objects_encoding(self): # See #12051 l, d = [], {} @@ -93,6 +97,7 @@ def test_highly_nested_objects_encoding(self): with self.assertRaises(RuntimeError): self.dumps(d) + @unittest.skipIf(test_support.is_jython, "See http://bugs.jython.org/issue2536.") def test_endless_recursion(self): # See #12051 class EndlessJSONEncoder(self.json.JSONEncoder): diff --git a/Lib/lib2to3/tests/test_main.py b/Lib/lib2to3/tests/test_main.py new file mode 100644 index 000000000..3d94f2983 --- /dev/null +++ b/Lib/lib2to3/tests/test_main.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +import sys +import codecs +import logging +import os +import re +import shutil +import StringIO +import sys +import tempfile +import unittest + +from lib2to3 import main + + +TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "data") +PY2_TEST_MODULE = os.path.join(TEST_DATA_DIR, "py2_test_grammar.py") + + +class TestMain(unittest.TestCase): + + if not hasattr(unittest.TestCase, 'assertNotRegex'): + # This method was only introduced in 3.2. + def assertNotRegex(self, text, regexp, msg=None): + import re + if not hasattr(regexp, 'search'): + regexp = re.compile(regexp) + if regexp.search(text): + self.fail("regexp %s MATCHED text %r" % (regexp.pattern, text)) + + def setUp(self): + self.temp_dir = None # tearDown() will rmtree this directory if set. + + def tearDown(self): + # Clean up logging configuration down by main. + del logging.root.handlers[:] + if self.temp_dir: + shutil.rmtree(self.temp_dir) + + def run_2to3_capture(self, args, in_capture, out_capture, err_capture): + save_stdin = sys.stdin + save_stdout = sys.stdout + save_stderr = sys.stderr + sys.stdin = in_capture + sys.stdout = out_capture + sys.stderr = err_capture + try: + return main.main("lib2to3.fixes", args) + finally: + sys.stdin = save_stdin + sys.stdout = save_stdout + sys.stderr = save_stderr + + def test_unencodable_diff(self): + input_stream = StringIO.StringIO(u"print 'nothing'\nprint u'über'\n") + out = StringIO.StringIO() + out_enc = codecs.getwriter("ascii")(out) + err = StringIO.StringIO() + ret = self.run_2to3_capture(["-"], input_stream, out_enc, err) + self.assertEqual(ret, 0) + output = out.getvalue() + self.assertTrue("-print 'nothing'" in output) + self.assertTrue("WARNING: couldn't encode 's diff for " + "your terminal" in err.getvalue()) + + def setup_test_source_trees(self): + """Setup a test source tree and output destination tree.""" + self.temp_dir = tempfile.mkdtemp() # tearDown() cleans this up. + + # Make the directory names unicode, in case the temporary directory has + # a non-ascii name, since refactor.py uses unicode strings internally. + # (Added for Jython but is test failure in CPython 2.7.13 too.) + self.temp_dir = self.temp_dir.decode(sys.getfilesystemencoding()) + + self.py2_src_dir = os.path.join(self.temp_dir, "python2_project") + self.py3_dest_dir = os.path.join(self.temp_dir, "python3_project") + os.mkdir(self.py2_src_dir) + os.mkdir(self.py3_dest_dir) + # Turn it into a package with a few files. + self.setup_files = [] + open(os.path.join(self.py2_src_dir, "__init__.py"), "w").close() + self.setup_files.append("__init__.py") + shutil.copy(PY2_TEST_MODULE, self.py2_src_dir) + self.setup_files.append(os.path.basename(PY2_TEST_MODULE)) + self.trivial_py2_file = os.path.join(self.py2_src_dir, "trivial.py") + self.init_py2_file = os.path.join(self.py2_src_dir, "__init__.py") + with open(self.trivial_py2_file, "w") as trivial: + trivial.write("print 'I need a simple conversion.'") + self.setup_files.append("trivial.py") + + def test_filename_changing_on_output_single_dir(self): + """2to3 a single directory with a new output dir and suffix.""" + self.setup_test_source_trees() + out = StringIO.StringIO() + err = StringIO.StringIO() + suffix = "TEST" + ret = self.run_2to3_capture( + ["-n", "--add-suffix", suffix, "--write-unchanged-files", + "--no-diffs", "--output-dir", + self.py3_dest_dir, self.py2_src_dir], + StringIO.StringIO(""), out, err) + self.assertEqual(ret, 0) + stderr = err.getvalue() + self.assertIn(" implies -w.", stderr) + self.assertIn( + "Output in %r will mirror the input directory %r layout" % ( + self.py3_dest_dir, self.py2_src_dir), stderr) + self.assertEqual(set(name+suffix for name in self.setup_files), + set(os.listdir(self.py3_dest_dir))) + for name in self.setup_files: + self.assertIn("Writing converted %s to %s" % ( + os.path.join(self.py2_src_dir, name), + os.path.join(self.py3_dest_dir, name+suffix)), stderr) + sep = re.escape(os.sep) + self.assertRegexpMatches( + stderr, r"No changes to .*/__init__\.py".replace("/", sep)) + self.assertNotRegex( + stderr, r"No changes to .*/trivial\.py".replace("/", sep)) + + def test_filename_changing_on_output_two_files(self): + """2to3 two files in one directory with a new output dir.""" + self.setup_test_source_trees() + err = StringIO.StringIO() + py2_files = [self.trivial_py2_file, self.init_py2_file] + expected_files = set(os.path.basename(name) for name in py2_files) + ret = self.run_2to3_capture( + ["-n", "-w", "--write-unchanged-files", + "--no-diffs", "--output-dir", self.py3_dest_dir] + py2_files, + StringIO.StringIO(""), StringIO.StringIO(), err) + self.assertEqual(ret, 0) + stderr = err.getvalue() + self.assertIn( + "Output in %r will mirror the input directory %r layout" % ( + self.py3_dest_dir, self.py2_src_dir), stderr) + self.assertEqual(expected_files, set(os.listdir(self.py3_dest_dir))) + + def test_filename_changing_on_output_single_file(self): + """2to3 a single file with a new output dir.""" + self.setup_test_source_trees() + err = StringIO.StringIO() + ret = self.run_2to3_capture( + ["-n", "-w", "--no-diffs", "--output-dir", self.py3_dest_dir, + self.trivial_py2_file], + StringIO.StringIO(""), StringIO.StringIO(), err) + self.assertEqual(ret, 0) + stderr = err.getvalue() + self.assertIn( + "Output in %r will mirror the input directory %r layout" % ( + self.py3_dest_dir, self.py2_src_dir), stderr) + self.assertEqual(set([os.path.basename(self.trivial_py2_file)]), + set(os.listdir(self.py3_dest_dir))) + + +if __name__ == '__main__': + unittest.main() diff --git a/Lib/lib2to3/tests/test_parser.py b/Lib/lib2to3/tests/test_parser.py new file mode 100644 index 000000000..6cdb96813 --- /dev/null +++ b/Lib/lib2to3/tests/test_parser.py @@ -0,0 +1,392 @@ +"""Test suite for 2to3's parser and grammar files. + +This is the place to add tests for changes to 2to3's grammar, such as those +merging the grammars for Python 2 and 3. In addition to specific tests for +parts of the grammar we've changed, we also make sure we can parse the +test_grammar.py files from both Python 2 and Python 3. +""" + +from __future__ import with_statement + +# Testing imports +from . import support +from .support import driver, test_dir +from test import test_support + + +# Python imports +import binascii +import operator +import os +import pickle +import shutil +import subprocess +import sys +import tempfile +import types +import unittest + +# Local imports +from lib2to3.pgen2 import driver as pgen2_driver +from lib2to3.pgen2 import tokenize +from ..pgen2.parse import ParseError +from lib2to3.pygram import python_symbols as syms + + +class TestDriver(support.TestCase): + + def test_formfeed(self): + s = """print 1\n\x0Cprint 2\n""" + t = driver.parse_string(s) + self.assertEqual(t.children[0].children[0].type, syms.print_stmt) + self.assertEqual(t.children[1].children[0].type, syms.print_stmt) + + +class TestPgen2Caching(support.TestCase): + def test_load_grammar_from_txt_file(self): + pgen2_driver.load_grammar(support.grammar_path, save=False, force=True) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + def test_load_grammar_from_pickle(self): + # Make a copy of the grammar file in a temp directory we are + # guaranteed to be able to write to. + tmpdir = tempfile.mkdtemp() + try: + grammar_copy = os.path.join( + tmpdir, os.path.basename(support.grammar_path)) + shutil.copy(support.grammar_path, grammar_copy) + pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) + + pgen2_driver.load_grammar(grammar_copy, save=True, force=True) + self.assertTrue(os.path.exists(pickle_name)) + + os.unlink(grammar_copy) # Only the pickle remains... + pgen2_driver.load_grammar(grammar_copy, save=False, force=False) + finally: + shutil.rmtree(tmpdir) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + @unittest.skipIf(sys.executable is None, 'sys.executable required') + def test_load_grammar_from_subprocess(self): + tmpdir = tempfile.mkdtemp() + tmpsubdir = os.path.join(tmpdir, 'subdir') + try: + os.mkdir(tmpsubdir) + grammar_base = os.path.basename(support.grammar_path) + grammar_copy = os.path.join(tmpdir, grammar_base) + grammar_sub_copy = os.path.join(tmpsubdir, grammar_base) + shutil.copy(support.grammar_path, grammar_copy) + shutil.copy(support.grammar_path, grammar_sub_copy) + pickle_name = pgen2_driver._generate_pickle_name(grammar_copy) + pickle_sub_name = pgen2_driver._generate_pickle_name( + grammar_sub_copy) + self.assertNotEqual(pickle_name, pickle_sub_name) + + # Generate a pickle file from this process. + pgen2_driver.load_grammar(grammar_copy, save=True, force=True) + self.assertTrue(os.path.exists(pickle_name)) + + # Generate a new pickle file in a subprocess with a most likely + # different hash randomization seed. + sub_env = dict(os.environ) + sub_env['PYTHONHASHSEED'] = 'random' + subprocess.check_call( + [sys.executable, '-c', """ +from lib2to3.pgen2 import driver as pgen2_driver +pgen2_driver.load_grammar(%r, save=True, force=True) + """ % (grammar_sub_copy,)], + env=sub_env) + self.assertTrue(os.path.exists(pickle_sub_name)) + + with open(pickle_name, 'rb') as pickle_f_1, \ + open(pickle_sub_name, 'rb') as pickle_f_2: + self.assertEqual( + pickle_f_1.read(), pickle_f_2.read(), + msg='Grammar caches generated using different hash seeds' + ' were not identical.') + finally: + shutil.rmtree(tmpdir) + + @unittest.skipIf(test_support.is_jython, "Not a valid test for Jython") + def test_load_packaged_grammar(self): + modname = __name__ + '.load_test' + class MyLoader: + def get_data(self, where): + return pickle.dumps({'elephant': 19}) + class MyModule(types.ModuleType): + __file__ = 'parsertestmodule' + __loader__ = MyLoader() + sys.modules[modname] = MyModule(modname) + self.addCleanup(operator.delitem, sys.modules, modname) + g = pgen2_driver.load_packaged_grammar(modname, 'Grammar.txt') + self.assertEqual(g.elephant, 19) + + +class GrammarTest(support.TestCase): + def validate(self, code): + support.parse_string(code) + + def invalid_syntax(self, code): + try: + self.validate(code) + except ParseError: + pass + else: + raise AssertionError("Syntax shouldn't have been valid") + + +class TestMatrixMultiplication(GrammarTest): + @unittest.skipIf(test_support.is_jython, "Not supported yet") + def test_matrix_multiplication_operator(self): + self.validate("a @ b") + self.validate("a @= b") + + +class TestYieldFrom(GrammarTest): + @unittest.skipIf(test_support.is_jython, "Not supported yet") + def test_matrix_multiplication_operator(self): + self.validate("yield from x") + self.validate("(yield from x) + y") + self.invalid_syntax("yield from") + + +class TestRaiseChanges(GrammarTest): + def test_2x_style_1(self): + self.validate("raise") + + def test_2x_style_2(self): + self.validate("raise E, V") + + def test_2x_style_3(self): + self.validate("raise E, V, T") + + def test_2x_style_invalid_1(self): + self.invalid_syntax("raise E, V, T, Z") + + def test_3x_style(self): + self.validate("raise E1 from E2") + + def test_3x_style_invalid_1(self): + self.invalid_syntax("raise E, V from E1") + + def test_3x_style_invalid_2(self): + self.invalid_syntax("raise E from E1, E2") + + def test_3x_style_invalid_3(self): + self.invalid_syntax("raise from E1, E2") + + def test_3x_style_invalid_4(self): + self.invalid_syntax("raise E from") + +# Modelled after Lib/test/test_grammar.py:TokenTests.test_funcdef issue2292 +# and Lib/test/text_parser.py test_list_displays, test_set_displays, +# test_dict_displays, test_argument_unpacking, ... changes. +class TestUnpackingGeneralizations(GrammarTest): + def test_mid_positional_star(self): + self.validate("""func(1, *(2, 3), 4)""") + + def test_double_star_dict_literal(self): + self.validate("""func(**{'eggs':'scrambled', 'spam':'fried'})""") + + def test_double_star_dict_literal_after_keywords(self): + self.validate("""func(spam='fried', **{'eggs':'scrambled'})""") + + def test_list_display(self): + self.validate("""[*{2}, 3, *[4]]""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_set_display(self): + self.validate("""{*{2}, 3, *[4]}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_dict_display_1(self): + self.validate("""{**{}}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_dict_display_2(self): + self.validate("""{**{}, 3:4, **{5:6, 7:8}}""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_1(self): + self.validate("""f(a, *b, *c, d)""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_2(self): + self.validate("""f(**a, **b)""") + + @unittest.skipIf(test_support.is_jython, "No Jython support yet") + def test_argument_unpacking_3(self): + self.validate("""f(2, *a, *b, **b, **c, **d)""") + + +# Adaptated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef +class TestFunctionAnnotations(GrammarTest): + def test_1(self): + self.validate("""def f(x) -> list: pass""") + + def test_2(self): + self.validate("""def f(x:int): pass""") + + def test_3(self): + self.validate("""def f(*x:str): pass""") + + def test_4(self): + self.validate("""def f(**x:float): pass""") + + def test_5(self): + self.validate("""def f(x, y:1+2): pass""") + + def test_6(self): + self.validate("""def f(a, (b:1, c:2, d)): pass""") + + def test_7(self): + self.validate("""def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass""") + + def test_8(self): + s = """def f(a, (b:1, c:2, d), e:3=4, f=5, + *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass""" + self.validate(s) + + +class TestExcept(GrammarTest): + def test_new(self): + s = """ + try: + x + except E as N: + y""" + self.validate(s) + + def test_old(self): + s = """ + try: + x + except E, N: + y""" + self.validate(s) + + +# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testAtoms +class TestSetLiteral(GrammarTest): + def test_1(self): + self.validate("""x = {'one'}""") + + def test_2(self): + self.validate("""x = {'one', 1,}""") + + def test_3(self): + self.validate("""x = {'one', 'two', 'three'}""") + + def test_4(self): + self.validate("""x = {2, 3, 4,}""") + + +class TestNumericLiterals(GrammarTest): + def test_new_octal_notation(self): + self.validate("""0o7777777777777""") + self.invalid_syntax("""0o7324528887""") + + def test_new_binary_notation(self): + self.validate("""0b101010""") + self.invalid_syntax("""0b0101021""") + + +class TestClassDef(GrammarTest): + def test_new_syntax(self): + self.validate("class B(t=7): pass") + self.validate("class B(t, *args): pass") + self.validate("class B(t, **kwargs): pass") + self.validate("class B(t, *args, **kwargs): pass") + self.validate("class B(t, y=9, *args, **kwargs): pass") + + +class TestParserIdempotency(support.TestCase): + + """A cut-down version of pytree_idempotency.py.""" + + def test_all_project_files(self): + for filepath in support.all_project_files(): + with open(filepath, "rb") as fp: + encoding = tokenize.detect_encoding(fp.readline)[0] + self.assertIsNotNone(encoding, + "can't detect encoding for %s" % filepath) + with open(filepath, "r") as fp: + source = fp.read() + source = source.decode(encoding) + tree = driver.parse_string(source) + new = unicode(tree) + diffResult = diff(filepath, new, encoding) + if diffResult: + self.fail("Idempotency failed: {} using {} encoding\n{}". + format(filepath,encoding,diffResult) ) + + def test_extended_unpacking(self): + driver.parse_string("a, *b, c = x\n") + driver.parse_string("[*a, b] = x\n") + driver.parse_string("(z, *y, w) = m\n") + driver.parse_string("for *z, m in d: pass\n") + + +class TestLiterals(GrammarTest): + + def validate(self, s): + driver.parse_string(support.dedent(s) + "\n\n") + + def test_multiline_bytes_literals(self): + s = """ + md5test(b"\xaa" * 80, + (b"Test Using Larger Than Block-Size Key " + b"and Larger Than One Block-Size Data"), + "6f630fad67cda0ee1fb1f562db3aa53e") + """ + self.validate(s) + + def test_multiline_bytes_tripquote_literals(self): + s = ''' + b""" + + + """ + ''' + self.validate(s) + + def test_multiline_str_literals(self): + s = """ + md5test("\xaa" * 80, + ("Test Using Larger Than Block-Size Key " + "and Larger Than One Block-Size Data"), + "6f630fad67cda0ee1fb1f562db3aa53e") + """ + self.validate(s) + + + +def diff(fn, result, encoding): + """Diff the result and original file content independent of OS. This + implementation is in Jython only. CPython 2.x calls out to the shell diff + command. CPython 3.x str equality behaviour is simpler and should allow + this test file to be replaced wholesale in Jython 3.x.""" + r = iter(result.encode(encoding).splitlines(True)) + lineNumber = 0 + with open(fn, "rbU") as f: + for line in f: + lineNumber += 1 + rline = next(r) + if rline != line: + return "original line {}:\n{}\n differs from:\n{}\n{}". \ + format(lineNumber, line, rline, diffLine(line, rline) ) + return False + +def diffLine(orig,result): + charNumber = 0 + for c in orig: + if c != result[charNumber]: + return "Lines differ at char {}: {} vs {} (of {} vs {})".format( + charNumber, + binascii.hexlify(c), + binascii.hexlify(result[charNumber]), + len(orig), + len(result) ) + charNumber += 1 + + diff --git a/Lib/locale.py b/Lib/locale.py new file mode 100644 index 000000000..344268dd8 --- /dev/null +++ b/Lib/locale.py @@ -0,0 +1,1891 @@ +""" Locale support. + + The module provides low-level access to the C lib's locale APIs + and adds high level number formatting APIs as well as a locale + aliasing engine to complement these. + + The aliasing engine includes support for many commonly used locale + names and maps them to values suitable for passing to the C lib's + setlocale() function. It also includes default encodings for all + supported locale names. + +""" + +import sys +import encodings +import encodings.aliases +import re +import operator +import functools + +try: + _unicode = unicode +except NameError: + # If Python is built without Unicode support, the unicode type + # will not exist. Fake one. + class _unicode(object): + pass + +# Try importing the _locale module. +# +# If this fails, fall back on a basic 'C' locale emulation. + +# Yuck: LC_MESSAGES is non-standard: can't tell whether it exists before +# trying the import. So __all__ is also fiddled at the end of the file. +__all__ = ["getlocale", "getdefaultlocale", "getpreferredencoding", "Error", + "setlocale", "resetlocale", "localeconv", "strcoll", "strxfrm", + "str", "atof", "atoi", "format", "format_string", "currency", + "normalize", "LC_CTYPE", "LC_COLLATE", "LC_TIME", "LC_MONETARY", + "LC_NUMERIC", "LC_ALL", "CHAR_MAX"] + +try: + + from _locale import * + +except ImportError: + + # Locale emulation + + CHAR_MAX = 127 + LC_ALL = 6 + LC_COLLATE = 3 + LC_CTYPE = 0 + LC_MESSAGES = 5 + LC_MONETARY = 4 + LC_NUMERIC = 1 + LC_TIME = 2 + Error = ValueError + + def localeconv(): + """ localeconv() -> dict. + Returns numeric and monetary locale-specific parameters. + """ + # 'C' locale default values + return {'grouping': [127], + 'currency_symbol': '', + 'n_sign_posn': 127, + 'p_cs_precedes': 127, + 'n_cs_precedes': 127, + 'mon_grouping': [], + 'n_sep_by_space': 127, + 'decimal_point': '.', + 'negative_sign': '', + 'positive_sign': '', + 'p_sep_by_space': 127, + 'int_curr_symbol': '', + 'p_sign_posn': 127, + 'thousands_sep': '', + 'mon_thousands_sep': '', + 'frac_digits': 127, + 'mon_decimal_point': '', + 'int_frac_digits': 127} + + def setlocale(category, value=None): + """ setlocale(integer,string=None) -> string. + Activates/queries locale processing. + """ + if value not in (None, '', 'C'): + raise Error, '_locale emulation only supports "C" locale' + return 'C' + + def strcoll(a,b): + """ strcoll(string,string) -> int. + Compares two strings according to the locale. + """ + return cmp(a,b) + + def strxfrm(s): + """ strxfrm(string) -> string. + Returns a string that behaves for cmp locale-aware. + """ + return s + + +_localeconv = localeconv + +# With this dict, you can override some items of localeconv's return value. +# This is useful for testing purposes. +_override_localeconv = {} + +@functools.wraps(_localeconv) +def localeconv(): + d = _localeconv() + if _override_localeconv: + d.update(_override_localeconv) + return d + + +### Number formatting APIs + +# Author: Martin von Loewis +# improved by Georg Brandl + +# Iterate over grouping intervals +def _grouping_intervals(grouping): + last_interval = None + for interval in grouping: + # if grouping is -1, we are done + if interval == CHAR_MAX: + return + # 0: re-use last group ad infinitum + if interval == 0: + if last_interval is None: + raise ValueError("invalid grouping") + while True: + yield last_interval + yield interval + last_interval = interval + +#perform the grouping from right to left +def _group(s, monetary=False): + conv = localeconv() + thousands_sep = conv[monetary and 'mon_thousands_sep' or 'thousands_sep'] + grouping = conv[monetary and 'mon_grouping' or 'grouping'] + if not grouping: + return (s, 0) + if s[-1] == ' ': + stripped = s.rstrip() + right_spaces = s[len(stripped):] + s = stripped + else: + right_spaces = '' + left_spaces = '' + groups = [] + for interval in _grouping_intervals(grouping): + if not s or s[-1] not in "0123456789": + # only non-digit characters remain (sign, spaces) + left_spaces = s + s = '' + break + groups.append(s[-interval:]) + s = s[:-interval] + if s: + groups.append(s) + groups.reverse() + return ( + left_spaces + thousands_sep.join(groups) + right_spaces, + len(thousands_sep) * (len(groups) - 1) + ) + +# Strip a given amount of excess padding from the given string +def _strip_padding(s, amount): + lpos = 0 + while amount and s[lpos] == ' ': + lpos += 1 + amount -= 1 + rpos = len(s) - 1 + while amount and s[rpos] == ' ': + rpos -= 1 + amount -= 1 + return s[lpos:rpos+1] + +_percent_re = re.compile(r'%(?:\((?P.*?)\))?' + r'(?P[-#0-9 +*.hlL]*?)[eEfFgGdiouxXcrs%]') + +def format(percent, value, grouping=False, monetary=False, *additional): + """Returns the locale-aware substitution of a %? specifier + (percent). + + additional is for format strings which contain one or more + '*' modifiers.""" + # this is only for one-percent-specifier strings and this should be checked + match = _percent_re.match(percent) + if not match or len(match.group())!= len(percent): + raise ValueError(("format() must be given exactly one %%char " + "format specifier, %s not valid") % repr(percent)) + return _format(percent, value, grouping, monetary, *additional) + +def _format(percent, value, grouping=False, monetary=False, *additional): + if additional: + formatted = percent % ((value,) + additional) + else: + formatted = percent % value + # floats and decimal ints need special action! + if percent[-1] in 'eEfFgG': + seps = 0 + parts = formatted.split('.') + if grouping: + parts[0], seps = _group(parts[0], monetary=monetary) + decimal_point = localeconv()[monetary and 'mon_decimal_point' + or 'decimal_point'] + formatted = decimal_point.join(parts) + if seps: + formatted = _strip_padding(formatted, seps) + elif percent[-1] in 'diu': + seps = 0 + if grouping: + formatted, seps = _group(formatted, monetary=monetary) + if seps: + formatted = _strip_padding(formatted, seps) + return formatted + +def format_string(f, val, grouping=False): + """Formats a string in the same way that the % formatting would use, + but takes the current locale into account. + Grouping is applied if the third parameter is true.""" + percents = list(_percent_re.finditer(f)) + new_f = _percent_re.sub('%s', f) + + if operator.isMappingType(val): + new_val = [] + for perc in percents: + if perc.group()[-1]=='%': + new_val.append('%') + else: + new_val.append(format(perc.group(), val, grouping)) + else: + if not isinstance(val, tuple): + val = (val,) + new_val = [] + i = 0 + for perc in percents: + if perc.group()[-1]=='%': + new_val.append('%') + else: + starcount = perc.group('modifiers').count('*') + new_val.append(_format(perc.group(), + val[i], + grouping, + False, + *val[i+1:i+1+starcount])) + i += (1 + starcount) + val = tuple(new_val) + + return new_f % val + +def currency(val, symbol=True, grouping=False, international=False): + """Formats val according to the currency settings + in the current locale.""" + conv = localeconv() + + # check for illegal values + digits = conv[international and 'int_frac_digits' or 'frac_digits'] + if digits == 127: + raise ValueError("Currency formatting is not possible using " + "the 'C' locale.") + + s = format('%%.%if' % digits, abs(val), grouping, monetary=True) + # '<' and '>' are markers if the sign must be inserted between symbol and value + s = '<' + s + '>' + + if symbol: + smb = conv[international and 'int_curr_symbol' or 'currency_symbol'] + precedes = conv[val<0 and 'n_cs_precedes' or 'p_cs_precedes'] + separated = conv[val<0 and 'n_sep_by_space' or 'p_sep_by_space'] + + if precedes: + s = smb + (separated and ' ' or '') + s + else: + s = s + (separated and ' ' or '') + smb + + sign_pos = conv[val<0 and 'n_sign_posn' or 'p_sign_posn'] + sign = conv[val<0 and 'negative_sign' or 'positive_sign'] + + if sign_pos == 0: + s = '(' + s + ')' + elif sign_pos == 1: + s = sign + s + elif sign_pos == 2: + s = s + sign + elif sign_pos == 3: + s = s.replace('<', sign) + elif sign_pos == 4: + s = s.replace('>', sign) + else: + # the default if nothing specified; + # this should be the most fitting sign position + s = sign + s + + return s.replace('<', '').replace('>', '') + +def str(val): + """Convert float to integer, taking the locale into account.""" + return format("%.12g", val) + +def atof(string, func=float): + "Parses a string as a float according to the locale settings." + #First, get rid of the grouping + ts = localeconv()['thousands_sep'] + if ts: + string = string.replace(ts, '') + #next, replace the decimal point with a dot + dd = localeconv()['decimal_point'] + if dd: + string = string.replace(dd, '.') + #finally, parse the string + return func(string) + +def atoi(str): + "Converts a string to an integer according to the locale settings." + return atof(str, int) + +def _test(): + setlocale(LC_ALL, "") + #do grouping + s1 = format("%d", 123456789,1) + print s1, "is", atoi(s1) + #standard formatting + s1 = str(3.14) + print s1, "is", atof(s1) + +### Locale name aliasing engine + +# Author: Marc-Andre Lemburg, mal@lemburg.com +# Various tweaks by Fredrik Lundh + +# store away the low-level version of setlocale (it's +# overridden below) +_setlocale = setlocale + +# Avoid relying on the locale-dependent .lower() method +# (see issue #1813). +_ascii_lower_map = ''.join( + chr(x + 32 if x >= ord('A') and x <= ord('Z') else x) + for x in range(256) +) + +def normalize(localename): + + """ Returns a normalized locale code for the given locale + name. + + The returned locale code is formatted for use with + setlocale(). + + If normalization fails, the original name is returned + unchanged. + + If the given encoding is not known, the function defaults to + the default encoding for the locale code just like setlocale() + does. + + """ + # Normalize the locale name and extract the encoding + if isinstance(localename, _unicode): + localename = localename.encode('ascii') + fullname = localename.translate(_ascii_lower_map) + if ':' in fullname: + # ':' is sometimes used as encoding delimiter. + fullname = fullname.replace(':', '.') + if '.' in fullname: + langname, encoding = fullname.split('.')[:2] + fullname = langname + '.' + encoding + else: + langname = fullname + encoding = '' + + # First lookup: fullname (possibly with encoding) + norm_encoding = encoding.replace('-', '') + norm_encoding = norm_encoding.replace('_', '') + lookup_name = langname + '.' + encoding + code = locale_alias.get(lookup_name, None) + if code is not None: + return code + #print 'first lookup failed' + + # Second try: langname (without encoding) + code = locale_alias.get(langname, None) + if code is not None: + #print 'langname lookup succeeded' + if '.' in code: + langname, defenc = code.split('.') + else: + langname = code + defenc = '' + if encoding: + # Convert the encoding to a C lib compatible encoding string + norm_encoding = encodings.normalize_encoding(encoding) + #print 'norm encoding: %r' % norm_encoding + norm_encoding = encodings.aliases.aliases.get(norm_encoding, + norm_encoding) + #print 'aliased encoding: %r' % norm_encoding + encoding = locale_encoding_alias.get(norm_encoding, + norm_encoding) + else: + encoding = defenc + #print 'found encoding %r' % encoding + if encoding: + return langname + '.' + encoding + else: + return langname + + else: + return localename + +def _parse_localename(localename): + + """ Parses the locale code for localename and returns the + result as tuple (language code, encoding). + + The localename is normalized and passed through the locale + alias engine. A ValueError is raised in case the locale name + cannot be parsed. + + The language code corresponds to RFC 1766. code and encoding + can be None in case the values cannot be determined or are + unknown to this implementation. + + """ + code = normalize(localename) + if '@' in code: + # Deal with locale modifiers + code, modifier = code.split('@') + if modifier == 'euro' and '.' not in code: + # Assume Latin-9 for @euro locales. This is bogus, + # since some systems may use other encodings for these + # locales. Also, we ignore other modifiers. + return code, 'iso-8859-15' + + if '.' in code: + return tuple(code.split('.')[:2]) + elif code == 'C': + return None, None + raise ValueError, 'unknown locale: %s' % localename + +def _build_localename(localetuple): + + """ Builds a locale code from the given tuple (language code, + encoding). + + No aliasing or normalizing takes place. + + """ + language, encoding = localetuple + if language is None: + language = 'C' + if encoding is None: + return language + else: + return language + '.' + encoding + +def getdefaultlocale(envvars=('LC_ALL', 'LC_CTYPE', 'LANG', 'LANGUAGE')): + + """ Tries to determine the default locale settings and returns + them as tuple (language code, encoding). + + According to POSIX, a program which has not called + setlocale(LC_ALL, "") runs using the portable 'C' locale. + Calling setlocale(LC_ALL, "") lets it use the default locale as + defined by the LANG variable. Since we don't want to interfere + with the current locale setting we thus emulate the behavior + in the way described above. + + To maintain compatibility with other platforms, not only the + LANG variable is tested, but a list of variables given as + envvars parameter. The first found to be defined will be + used. envvars defaults to the search path used in GNU gettext; + it must always contain the variable name 'LANG'. + + Except for the code 'C', the language code corresponds to RFC + 1766. code and encoding can be None in case the values cannot + be determined. + + """ + + if sys.platform.startswith("java"): + from java.util import Locale + from java.nio.charset import Charset + return Locale.getDefault().toString().__str__(), \ + Charset.defaultCharset().name().__str__() + try: + # check if it's supported by the _locale module + import _locale + code, encoding = _locale._getdefaultlocale() + except (ImportError, AttributeError): + pass + else: + # make sure the code/encoding values are valid + if sys.platform == "win32" and code and code[:2] == "0x": + # map windows language identifier to language name + code = windows_locale.get(int(code, 0)) + # ...add other platform-specific processing here, if + # necessary... + return code, encoding + + # fall back on POSIX behaviour + import os + lookup = os.environ.get + for variable in envvars: + localename = lookup(variable,None) + if localename: + if variable == 'LANGUAGE': + localename = localename.split(':')[0] + break + else: + localename = 'C' + return _parse_localename(localename) + + +def getlocale(category=LC_CTYPE): + + """ Returns the current setting for the given locale category as + tuple (language code, encoding). + + category may be one of the LC_* value except LC_ALL. It + defaults to LC_CTYPE. + + Except for the code 'C', the language code corresponds to RFC + 1766. code and encoding can be None in case the values cannot + be determined. + + """ + localename = _setlocale(category) + if category == LC_ALL and ';' in localename: + raise TypeError, 'category LC_ALL is not supported' + return _parse_localename(localename) + +def setlocale(category, locale=None): + + """ Set the locale for the given category. The locale can be + a string, an iterable of two strings (language code and encoding), + or None. + + Iterables are converted to strings using the locale aliasing + engine. Locale strings are passed directly to the C lib. + + category may be given as one of the LC_* values. + + """ + if locale and type(locale) is not type(""): + # convert to string + locale = normalize(_build_localename(locale)) + return _setlocale(category, locale) + +def resetlocale(category=LC_ALL): + + """ Sets the locale for category to the default setting. + + The default setting is determined by calling + getdefaultlocale(). category defaults to LC_ALL. + + """ + _setlocale(category, _build_localename(getdefaultlocale())) + +if sys.platform.startswith("java"): + from java.nio.charset import Charset + def getpreferredencoding(do_setlocale = True): + return Charset.defaultCharset().name().__str__() +elif sys.platform.startswith("win"): + # On Win32, this will return the ANSI code page + def getpreferredencoding(do_setlocale = True): + """Return the charset that the user is likely using.""" + import _locale + return _locale._getdefaultlocale()[1] +else: + # On Unix, if CODESET is available, use that. + try: + CODESET + except NameError: + # Fall back to parsing environment variables :-( + def getpreferredencoding(do_setlocale = True): + """Return the charset that the user is likely using, + by looking at environment variables.""" + return getdefaultlocale()[1] + else: + def getpreferredencoding(do_setlocale = True): + """Return the charset that the user is likely using, + according to the system configuration.""" + if do_setlocale: + oldloc = setlocale(LC_CTYPE) + try: + setlocale(LC_CTYPE, "") + except Error: + pass + result = nl_langinfo(CODESET) + setlocale(LC_CTYPE, oldloc) + return result + else: + return nl_langinfo(CODESET) + + +### Database +# +# The following data was extracted from the locale.alias file which +# comes with X11 and then hand edited removing the explicit encoding +# definitions and adding some more aliases. The file is usually +# available as /usr/lib/X11/locale/locale.alias. +# + +# +# The local_encoding_alias table maps lowercase encoding alias names +# to C locale encoding names (case-sensitive). Note that normalize() +# first looks up the encoding in the encodings.aliases dictionary and +# then applies this mapping to find the correct C lib name for the +# encoding. +# +locale_encoding_alias = { + + # Mappings for non-standard encoding names used in locale names + '437': 'C', + 'c': 'C', + 'en': 'ISO8859-1', + 'jis': 'JIS7', + 'jis7': 'JIS7', + 'ajec': 'eucJP', + + # Mappings from Python codec names to C lib encoding names + 'ascii': 'ISO8859-1', + 'latin_1': 'ISO8859-1', + 'iso8859_1': 'ISO8859-1', + 'iso8859_10': 'ISO8859-10', + 'iso8859_11': 'ISO8859-11', + 'iso8859_13': 'ISO8859-13', + 'iso8859_14': 'ISO8859-14', + 'iso8859_15': 'ISO8859-15', + 'iso8859_16': 'ISO8859-16', + 'iso8859_2': 'ISO8859-2', + 'iso8859_3': 'ISO8859-3', + 'iso8859_4': 'ISO8859-4', + 'iso8859_5': 'ISO8859-5', + 'iso8859_6': 'ISO8859-6', + 'iso8859_7': 'ISO8859-7', + 'iso8859_8': 'ISO8859-8', + 'iso8859_9': 'ISO8859-9', + 'iso2022_jp': 'JIS7', + 'shift_jis': 'SJIS', + 'tactis': 'TACTIS', + 'euc_jp': 'eucJP', + 'euc_kr': 'eucKR', + 'utf_8': 'UTF-8', + 'koi8_r': 'KOI8-R', + 'koi8_u': 'KOI8-U', + # XXX This list is still incomplete. If you know more + # mappings, please file a bug report. Thanks. +} + +# +# The locale_alias table maps lowercase alias names to C locale names +# (case-sensitive). Encodings are always separated from the locale +# name using a dot ('.'); they should only be given in case the +# language name is needed to interpret the given encoding alias +# correctly (CJK codes often have this need). +# +# Note that the normalize() function which uses this tables +# removes '_' and '-' characters from the encoding part of the +# locale name before doing the lookup. This saves a lot of +# space in the table. +# +# MAL 2004-12-10: +# Updated alias mapping to most recent locale.alias file +# from X.org distribution using makelocalealias.py. +# +# These are the differences compared to the old mapping (Python 2.4 +# and older): +# +# updated 'bg' -> 'bg_BG.ISO8859-5' to 'bg_BG.CP1251' +# updated 'bg_bg' -> 'bg_BG.ISO8859-5' to 'bg_BG.CP1251' +# updated 'bulgarian' -> 'bg_BG.ISO8859-5' to 'bg_BG.CP1251' +# updated 'cz' -> 'cz_CZ.ISO8859-2' to 'cs_CZ.ISO8859-2' +# updated 'cz_cz' -> 'cz_CZ.ISO8859-2' to 'cs_CZ.ISO8859-2' +# updated 'czech' -> 'cs_CS.ISO8859-2' to 'cs_CZ.ISO8859-2' +# updated 'dutch' -> 'nl_BE.ISO8859-1' to 'nl_NL.ISO8859-1' +# updated 'et' -> 'et_EE.ISO8859-4' to 'et_EE.ISO8859-15' +# updated 'et_ee' -> 'et_EE.ISO8859-4' to 'et_EE.ISO8859-15' +# updated 'fi' -> 'fi_FI.ISO8859-1' to 'fi_FI.ISO8859-15' +# updated 'fi_fi' -> 'fi_FI.ISO8859-1' to 'fi_FI.ISO8859-15' +# updated 'iw' -> 'iw_IL.ISO8859-8' to 'he_IL.ISO8859-8' +# updated 'iw_il' -> 'iw_IL.ISO8859-8' to 'he_IL.ISO8859-8' +# updated 'japanese' -> 'ja_JP.SJIS' to 'ja_JP.eucJP' +# updated 'lt' -> 'lt_LT.ISO8859-4' to 'lt_LT.ISO8859-13' +# updated 'lv' -> 'lv_LV.ISO8859-4' to 'lv_LV.ISO8859-13' +# updated 'sl' -> 'sl_CS.ISO8859-2' to 'sl_SI.ISO8859-2' +# updated 'slovene' -> 'sl_CS.ISO8859-2' to 'sl_SI.ISO8859-2' +# updated 'th_th' -> 'th_TH.TACTIS' to 'th_TH.ISO8859-11' +# updated 'zh_cn' -> 'zh_CN.eucCN' to 'zh_CN.gb2312' +# updated 'zh_cn.big5' -> 'zh_TW.eucTW' to 'zh_TW.big5' +# updated 'zh_tw' -> 'zh_TW.eucTW' to 'zh_TW.big5' +# +# MAL 2008-05-30: +# Updated alias mapping to most recent locale.alias file +# from X.org distribution using makelocalealias.py. +# +# These are the differences compared to the old mapping (Python 2.5 +# and older): +# +# updated 'cs_cs.iso88592' -> 'cs_CZ.ISO8859-2' to 'cs_CS.ISO8859-2' +# updated 'serbocroatian' -> 'sh_YU.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sh' -> 'sh_YU.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sh_hr.iso88592' -> 'sh_HR.ISO8859-2' to 'hr_HR.ISO8859-2' +# updated 'sh_sp' -> 'sh_YU.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sh_yu' -> 'sh_YU.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sp' -> 'sp_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sp_yu' -> 'sp_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr@cyrillic' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr_sp' -> 'sr_SP.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sr_yu' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr_yu.cp1251@cyrillic' -> 'sr_YU.CP1251' to 'sr_CS.CP1251' +# updated 'sr_yu.iso88592' -> 'sr_YU.ISO8859-2' to 'sr_CS.ISO8859-2' +# updated 'sr_yu.iso88595' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr_yu.iso88595@cyrillic' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# updated 'sr_yu.microsoftcp1251@cyrillic' -> 'sr_YU.CP1251' to 'sr_CS.CP1251' +# updated 'sr_yu.utf8@cyrillic' -> 'sr_YU.UTF-8' to 'sr_CS.UTF-8' +# updated 'sr_yu@cyrillic' -> 'sr_YU.ISO8859-5' to 'sr_CS.ISO8859-5' +# +# AP 2010-04-12: +# Updated alias mapping to most recent locale.alias file +# from X.org distribution using makelocalealias.py. +# +# These are the differences compared to the old mapping (Python 2.6.5 +# and older): +# +# updated 'ru' -> 'ru_RU.ISO8859-5' to 'ru_RU.UTF-8' +# updated 'ru_ru' -> 'ru_RU.ISO8859-5' to 'ru_RU.UTF-8' +# updated 'serbocroatian' -> 'sr_CS.ISO8859-2' to 'sr_RS.UTF-8@latin' +# updated 'sh' -> 'sr_CS.ISO8859-2' to 'sr_RS.UTF-8@latin' +# updated 'sh_yu' -> 'sr_CS.ISO8859-2' to 'sr_RS.UTF-8@latin' +# updated 'sr' -> 'sr_CS.ISO8859-5' to 'sr_RS.UTF-8' +# updated 'sr@cyrillic' -> 'sr_CS.ISO8859-5' to 'sr_RS.UTF-8' +# updated 'sr@latn' -> 'sr_CS.ISO8859-2' to 'sr_RS.UTF-8@latin' +# updated 'sr_cs.utf8@latn' -> 'sr_CS.UTF-8' to 'sr_RS.UTF-8@latin' +# updated 'sr_cs@latn' -> 'sr_CS.ISO8859-2' to 'sr_RS.UTF-8@latin' +# updated 'sr_yu' -> 'sr_CS.ISO8859-5' to 'sr_RS.UTF-8@latin' +# updated 'sr_yu.utf8@cyrillic' -> 'sr_CS.UTF-8' to 'sr_RS.UTF-8' +# updated 'sr_yu@cyrillic' -> 'sr_CS.ISO8859-5' to 'sr_RS.UTF-8' +# + +locale_alias = { + 'a3': 'a3_AZ.KOI8-C', + 'a3_az': 'a3_AZ.KOI8-C', + 'a3_az.koi8c': 'a3_AZ.KOI8-C', + 'af': 'af_ZA.ISO8859-1', + 'af_za': 'af_ZA.ISO8859-1', + 'af_za.iso88591': 'af_ZA.ISO8859-1', + 'am': 'am_ET.UTF-8', + 'am_et': 'am_ET.UTF-8', + 'american': 'en_US.ISO8859-1', + 'american.iso88591': 'en_US.ISO8859-1', + 'ar': 'ar_AA.ISO8859-6', + 'ar_aa': 'ar_AA.ISO8859-6', + 'ar_aa.iso88596': 'ar_AA.ISO8859-6', + 'ar_ae': 'ar_AE.ISO8859-6', + 'ar_ae.iso88596': 'ar_AE.ISO8859-6', + 'ar_bh': 'ar_BH.ISO8859-6', + 'ar_bh.iso88596': 'ar_BH.ISO8859-6', + 'ar_dz': 'ar_DZ.ISO8859-6', + 'ar_dz.iso88596': 'ar_DZ.ISO8859-6', + 'ar_eg': 'ar_EG.ISO8859-6', + 'ar_eg.iso88596': 'ar_EG.ISO8859-6', + 'ar_iq': 'ar_IQ.ISO8859-6', + 'ar_iq.iso88596': 'ar_IQ.ISO8859-6', + 'ar_jo': 'ar_JO.ISO8859-6', + 'ar_jo.iso88596': 'ar_JO.ISO8859-6', + 'ar_kw': 'ar_KW.ISO8859-6', + 'ar_kw.iso88596': 'ar_KW.ISO8859-6', + 'ar_lb': 'ar_LB.ISO8859-6', + 'ar_lb.iso88596': 'ar_LB.ISO8859-6', + 'ar_ly': 'ar_LY.ISO8859-6', + 'ar_ly.iso88596': 'ar_LY.ISO8859-6', + 'ar_ma': 'ar_MA.ISO8859-6', + 'ar_ma.iso88596': 'ar_MA.ISO8859-6', + 'ar_om': 'ar_OM.ISO8859-6', + 'ar_om.iso88596': 'ar_OM.ISO8859-6', + 'ar_qa': 'ar_QA.ISO8859-6', + 'ar_qa.iso88596': 'ar_QA.ISO8859-6', + 'ar_sa': 'ar_SA.ISO8859-6', + 'ar_sa.iso88596': 'ar_SA.ISO8859-6', + 'ar_sd': 'ar_SD.ISO8859-6', + 'ar_sd.iso88596': 'ar_SD.ISO8859-6', + 'ar_sy': 'ar_SY.ISO8859-6', + 'ar_sy.iso88596': 'ar_SY.ISO8859-6', + 'ar_tn': 'ar_TN.ISO8859-6', + 'ar_tn.iso88596': 'ar_TN.ISO8859-6', + 'ar_ye': 'ar_YE.ISO8859-6', + 'ar_ye.iso88596': 'ar_YE.ISO8859-6', + 'arabic': 'ar_AA.ISO8859-6', + 'arabic.iso88596': 'ar_AA.ISO8859-6', + 'as': 'as_IN.UTF-8', + 'az': 'az_AZ.ISO8859-9E', + 'az_az': 'az_AZ.ISO8859-9E', + 'az_az.iso88599e': 'az_AZ.ISO8859-9E', + 'be': 'be_BY.CP1251', + 'be@latin': 'be_BY.UTF-8@latin', + 'be_by': 'be_BY.CP1251', + 'be_by.cp1251': 'be_BY.CP1251', + 'be_by.microsoftcp1251': 'be_BY.CP1251', + 'be_by.utf8@latin': 'be_BY.UTF-8@latin', + 'be_by@latin': 'be_BY.UTF-8@latin', + 'bg': 'bg_BG.CP1251', + 'bg_bg': 'bg_BG.CP1251', + 'bg_bg.cp1251': 'bg_BG.CP1251', + 'bg_bg.iso88595': 'bg_BG.ISO8859-5', + 'bg_bg.koi8r': 'bg_BG.KOI8-R', + 'bg_bg.microsoftcp1251': 'bg_BG.CP1251', + 'bn_in': 'bn_IN.UTF-8', + 'bokmal': 'nb_NO.ISO8859-1', + 'bokm\xe5l': 'nb_NO.ISO8859-1', + 'br': 'br_FR.ISO8859-1', + 'br_fr': 'br_FR.ISO8859-1', + 'br_fr.iso88591': 'br_FR.ISO8859-1', + 'br_fr.iso885914': 'br_FR.ISO8859-14', + 'br_fr.iso885915': 'br_FR.ISO8859-15', + 'br_fr.iso885915@euro': 'br_FR.ISO8859-15', + 'br_fr.utf8@euro': 'br_FR.UTF-8', + 'br_fr@euro': 'br_FR.ISO8859-15', + 'bs': 'bs_BA.ISO8859-2', + 'bs_ba': 'bs_BA.ISO8859-2', + 'bs_ba.iso88592': 'bs_BA.ISO8859-2', + 'bulgarian': 'bg_BG.CP1251', + 'c': 'C', + 'c-french': 'fr_CA.ISO8859-1', + 'c-french.iso88591': 'fr_CA.ISO8859-1', + 'c.en': 'C', + 'c.iso88591': 'en_US.ISO8859-1', + 'c_c': 'C', + 'c_c.c': 'C', + 'ca': 'ca_ES.ISO8859-1', + 'ca_ad': 'ca_AD.ISO8859-1', + 'ca_ad.iso88591': 'ca_AD.ISO8859-1', + 'ca_ad.iso885915': 'ca_AD.ISO8859-15', + 'ca_ad.iso885915@euro': 'ca_AD.ISO8859-15', + 'ca_ad.utf8@euro': 'ca_AD.UTF-8', + 'ca_ad@euro': 'ca_AD.ISO8859-15', + 'ca_es': 'ca_ES.ISO8859-1', + 'ca_es.iso88591': 'ca_ES.ISO8859-1', + 'ca_es.iso885915': 'ca_ES.ISO8859-15', + 'ca_es.iso885915@euro': 'ca_ES.ISO8859-15', + 'ca_es.utf8@euro': 'ca_ES.UTF-8', + 'ca_es@euro': 'ca_ES.ISO8859-15', + 'ca_fr': 'ca_FR.ISO8859-1', + 'ca_fr.iso88591': 'ca_FR.ISO8859-1', + 'ca_fr.iso885915': 'ca_FR.ISO8859-15', + 'ca_fr.iso885915@euro': 'ca_FR.ISO8859-15', + 'ca_fr.utf8@euro': 'ca_FR.UTF-8', + 'ca_fr@euro': 'ca_FR.ISO8859-15', + 'ca_it': 'ca_IT.ISO8859-1', + 'ca_it.iso88591': 'ca_IT.ISO8859-1', + 'ca_it.iso885915': 'ca_IT.ISO8859-15', + 'ca_it.iso885915@euro': 'ca_IT.ISO8859-15', + 'ca_it.utf8@euro': 'ca_IT.UTF-8', + 'ca_it@euro': 'ca_IT.ISO8859-15', + 'catalan': 'ca_ES.ISO8859-1', + 'cextend': 'en_US.ISO8859-1', + 'cextend.en': 'en_US.ISO8859-1', + 'chinese-s': 'zh_CN.eucCN', + 'chinese-t': 'zh_TW.eucTW', + 'croatian': 'hr_HR.ISO8859-2', + 'cs': 'cs_CZ.ISO8859-2', + 'cs_cs': 'cs_CZ.ISO8859-2', + 'cs_cs.iso88592': 'cs_CS.ISO8859-2', + 'cs_cz': 'cs_CZ.ISO8859-2', + 'cs_cz.iso88592': 'cs_CZ.ISO8859-2', + 'cy': 'cy_GB.ISO8859-1', + 'cy_gb': 'cy_GB.ISO8859-1', + 'cy_gb.iso88591': 'cy_GB.ISO8859-1', + 'cy_gb.iso885914': 'cy_GB.ISO8859-14', + 'cy_gb.iso885915': 'cy_GB.ISO8859-15', + 'cy_gb@euro': 'cy_GB.ISO8859-15', + 'cz': 'cs_CZ.ISO8859-2', + 'cz_cz': 'cs_CZ.ISO8859-2', + 'czech': 'cs_CZ.ISO8859-2', + 'da': 'da_DK.ISO8859-1', + 'da.iso885915': 'da_DK.ISO8859-15', + 'da_dk': 'da_DK.ISO8859-1', + 'da_dk.88591': 'da_DK.ISO8859-1', + 'da_dk.885915': 'da_DK.ISO8859-15', + 'da_dk.iso88591': 'da_DK.ISO8859-1', + 'da_dk.iso885915': 'da_DK.ISO8859-15', + 'da_dk@euro': 'da_DK.ISO8859-15', + 'danish': 'da_DK.ISO8859-1', + 'danish.iso88591': 'da_DK.ISO8859-1', + 'dansk': 'da_DK.ISO8859-1', + 'de': 'de_DE.ISO8859-1', + 'de.iso885915': 'de_DE.ISO8859-15', + 'de_at': 'de_AT.ISO8859-1', + 'de_at.iso88591': 'de_AT.ISO8859-1', + 'de_at.iso885915': 'de_AT.ISO8859-15', + 'de_at.iso885915@euro': 'de_AT.ISO8859-15', + 'de_at.utf8@euro': 'de_AT.UTF-8', + 'de_at@euro': 'de_AT.ISO8859-15', + 'de_be': 'de_BE.ISO8859-1', + 'de_be.iso88591': 'de_BE.ISO8859-1', + 'de_be.iso885915': 'de_BE.ISO8859-15', + 'de_be.iso885915@euro': 'de_BE.ISO8859-15', + 'de_be.utf8@euro': 'de_BE.UTF-8', + 'de_be@euro': 'de_BE.ISO8859-15', + 'de_ch': 'de_CH.ISO8859-1', + 'de_ch.iso88591': 'de_CH.ISO8859-1', + 'de_ch.iso885915': 'de_CH.ISO8859-15', + 'de_ch@euro': 'de_CH.ISO8859-15', + 'de_de': 'de_DE.ISO8859-1', + 'de_de.88591': 'de_DE.ISO8859-1', + 'de_de.885915': 'de_DE.ISO8859-15', + 'de_de.885915@euro': 'de_DE.ISO8859-15', + 'de_de.iso88591': 'de_DE.ISO8859-1', + 'de_de.iso885915': 'de_DE.ISO8859-15', + 'de_de.iso885915@euro': 'de_DE.ISO8859-15', + 'de_de.utf8@euro': 'de_DE.UTF-8', + 'de_de@euro': 'de_DE.ISO8859-15', + 'de_lu': 'de_LU.ISO8859-1', + 'de_lu.iso88591': 'de_LU.ISO8859-1', + 'de_lu.iso885915': 'de_LU.ISO8859-15', + 'de_lu.iso885915@euro': 'de_LU.ISO8859-15', + 'de_lu.utf8@euro': 'de_LU.UTF-8', + 'de_lu@euro': 'de_LU.ISO8859-15', + 'deutsch': 'de_DE.ISO8859-1', + 'dutch': 'nl_NL.ISO8859-1', + 'dutch.iso88591': 'nl_BE.ISO8859-1', + 'ee': 'ee_EE.ISO8859-4', + 'ee_ee': 'ee_EE.ISO8859-4', + 'ee_ee.iso88594': 'ee_EE.ISO8859-4', + 'eesti': 'et_EE.ISO8859-1', + 'el': 'el_GR.ISO8859-7', + 'el_gr': 'el_GR.ISO8859-7', + 'el_gr.iso88597': 'el_GR.ISO8859-7', + 'el_gr@euro': 'el_GR.ISO8859-15', + 'en': 'en_US.ISO8859-1', + 'en.iso88591': 'en_US.ISO8859-1', + 'en_au': 'en_AU.ISO8859-1', + 'en_au.iso88591': 'en_AU.ISO8859-1', + 'en_be': 'en_BE.ISO8859-1', + 'en_be@euro': 'en_BE.ISO8859-15', + 'en_bw': 'en_BW.ISO8859-1', + 'en_bw.iso88591': 'en_BW.ISO8859-1', + 'en_ca': 'en_CA.ISO8859-1', + 'en_ca.iso88591': 'en_CA.ISO8859-1', + 'en_gb': 'en_GB.ISO8859-1', + 'en_gb.88591': 'en_GB.ISO8859-1', + 'en_gb.iso88591': 'en_GB.ISO8859-1', + 'en_gb.iso885915': 'en_GB.ISO8859-15', + 'en_gb@euro': 'en_GB.ISO8859-15', + 'en_hk': 'en_HK.ISO8859-1', + 'en_hk.iso88591': 'en_HK.ISO8859-1', + 'en_ie': 'en_IE.ISO8859-1', + 'en_ie.iso88591': 'en_IE.ISO8859-1', + 'en_ie.iso885915': 'en_IE.ISO8859-15', + 'en_ie.iso885915@euro': 'en_IE.ISO8859-15', + 'en_ie.utf8@euro': 'en_IE.UTF-8', + 'en_ie@euro': 'en_IE.ISO8859-15', + 'en_in': 'en_IN.ISO8859-1', + 'en_nz': 'en_NZ.ISO8859-1', + 'en_nz.iso88591': 'en_NZ.ISO8859-1', + 'en_ph': 'en_PH.ISO8859-1', + 'en_ph.iso88591': 'en_PH.ISO8859-1', + 'en_sg': 'en_SG.ISO8859-1', + 'en_sg.iso88591': 'en_SG.ISO8859-1', + 'en_uk': 'en_GB.ISO8859-1', + 'en_us': 'en_US.ISO8859-1', + 'en_us.88591': 'en_US.ISO8859-1', + 'en_us.885915': 'en_US.ISO8859-15', + 'en_us.iso88591': 'en_US.ISO8859-1', + 'en_us.iso885915': 'en_US.ISO8859-15', + 'en_us.iso885915@euro': 'en_US.ISO8859-15', + 'en_us@euro': 'en_US.ISO8859-15', + 'en_us@euro@euro': 'en_US.ISO8859-15', + 'en_za': 'en_ZA.ISO8859-1', + 'en_za.88591': 'en_ZA.ISO8859-1', + 'en_za.iso88591': 'en_ZA.ISO8859-1', + 'en_za.iso885915': 'en_ZA.ISO8859-15', + 'en_za@euro': 'en_ZA.ISO8859-15', + 'en_zw': 'en_ZW.ISO8859-1', + 'en_zw.iso88591': 'en_ZW.ISO8859-1', + 'eng_gb': 'en_GB.ISO8859-1', + 'eng_gb.8859': 'en_GB.ISO8859-1', + 'english': 'en_EN.ISO8859-1', + 'english.iso88591': 'en_EN.ISO8859-1', + 'english_uk': 'en_GB.ISO8859-1', + 'english_uk.8859': 'en_GB.ISO8859-1', + 'english_united-states': 'en_US.ISO8859-1', + 'english_united-states.437': 'C', + 'english_us': 'en_US.ISO8859-1', + 'english_us.8859': 'en_US.ISO8859-1', + 'english_us.ascii': 'en_US.ISO8859-1', + 'eo': 'eo_XX.ISO8859-3', + 'eo_eo': 'eo_EO.ISO8859-3', + 'eo_eo.iso88593': 'eo_EO.ISO8859-3', + 'eo_xx': 'eo_XX.ISO8859-3', + 'eo_xx.iso88593': 'eo_XX.ISO8859-3', + 'es': 'es_ES.ISO8859-1', + 'es_ar': 'es_AR.ISO8859-1', + 'es_ar.iso88591': 'es_AR.ISO8859-1', + 'es_bo': 'es_BO.ISO8859-1', + 'es_bo.iso88591': 'es_BO.ISO8859-1', + 'es_cl': 'es_CL.ISO8859-1', + 'es_cl.iso88591': 'es_CL.ISO8859-1', + 'es_co': 'es_CO.ISO8859-1', + 'es_co.iso88591': 'es_CO.ISO8859-1', + 'es_cr': 'es_CR.ISO8859-1', + 'es_cr.iso88591': 'es_CR.ISO8859-1', + 'es_do': 'es_DO.ISO8859-1', + 'es_do.iso88591': 'es_DO.ISO8859-1', + 'es_ec': 'es_EC.ISO8859-1', + 'es_ec.iso88591': 'es_EC.ISO8859-1', + 'es_es': 'es_ES.ISO8859-1', + 'es_es.88591': 'es_ES.ISO8859-1', + 'es_es.iso88591': 'es_ES.ISO8859-1', + 'es_es.iso885915': 'es_ES.ISO8859-15', + 'es_es.iso885915@euro': 'es_ES.ISO8859-15', + 'es_es.utf8@euro': 'es_ES.UTF-8', + 'es_es@euro': 'es_ES.ISO8859-15', + 'es_gt': 'es_GT.ISO8859-1', + 'es_gt.iso88591': 'es_GT.ISO8859-1', + 'es_hn': 'es_HN.ISO8859-1', + 'es_hn.iso88591': 'es_HN.ISO8859-1', + 'es_mx': 'es_MX.ISO8859-1', + 'es_mx.iso88591': 'es_MX.ISO8859-1', + 'es_ni': 'es_NI.ISO8859-1', + 'es_ni.iso88591': 'es_NI.ISO8859-1', + 'es_pa': 'es_PA.ISO8859-1', + 'es_pa.iso88591': 'es_PA.ISO8859-1', + 'es_pa.iso885915': 'es_PA.ISO8859-15', + 'es_pa@euro': 'es_PA.ISO8859-15', + 'es_pe': 'es_PE.ISO8859-1', + 'es_pe.iso88591': 'es_PE.ISO8859-1', + 'es_pe.iso885915': 'es_PE.ISO8859-15', + 'es_pe@euro': 'es_PE.ISO8859-15', + 'es_pr': 'es_PR.ISO8859-1', + 'es_pr.iso88591': 'es_PR.ISO8859-1', + 'es_py': 'es_PY.ISO8859-1', + 'es_py.iso88591': 'es_PY.ISO8859-1', + 'es_py.iso885915': 'es_PY.ISO8859-15', + 'es_py@euro': 'es_PY.ISO8859-15', + 'es_sv': 'es_SV.ISO8859-1', + 'es_sv.iso88591': 'es_SV.ISO8859-1', + 'es_sv.iso885915': 'es_SV.ISO8859-15', + 'es_sv@euro': 'es_SV.ISO8859-15', + 'es_us': 'es_US.ISO8859-1', + 'es_us.iso88591': 'es_US.ISO8859-1', + 'es_uy': 'es_UY.ISO8859-1', + 'es_uy.iso88591': 'es_UY.ISO8859-1', + 'es_uy.iso885915': 'es_UY.ISO8859-15', + 'es_uy@euro': 'es_UY.ISO8859-15', + 'es_ve': 'es_VE.ISO8859-1', + 'es_ve.iso88591': 'es_VE.ISO8859-1', + 'es_ve.iso885915': 'es_VE.ISO8859-15', + 'es_ve@euro': 'es_VE.ISO8859-15', + 'estonian': 'et_EE.ISO8859-1', + 'et': 'et_EE.ISO8859-15', + 'et_ee': 'et_EE.ISO8859-15', + 'et_ee.iso88591': 'et_EE.ISO8859-1', + 'et_ee.iso885913': 'et_EE.ISO8859-13', + 'et_ee.iso885915': 'et_EE.ISO8859-15', + 'et_ee.iso88594': 'et_EE.ISO8859-4', + 'et_ee@euro': 'et_EE.ISO8859-15', + 'eu': 'eu_ES.ISO8859-1', + 'eu_es': 'eu_ES.ISO8859-1', + 'eu_es.iso88591': 'eu_ES.ISO8859-1', + 'eu_es.iso885915': 'eu_ES.ISO8859-15', + 'eu_es.iso885915@euro': 'eu_ES.ISO8859-15', + 'eu_es.utf8@euro': 'eu_ES.UTF-8', + 'eu_es@euro': 'eu_ES.ISO8859-15', + 'fa': 'fa_IR.UTF-8', + 'fa_ir': 'fa_IR.UTF-8', + 'fa_ir.isiri3342': 'fa_IR.ISIRI-3342', + 'fi': 'fi_FI.ISO8859-15', + 'fi.iso885915': 'fi_FI.ISO8859-15', + 'fi_fi': 'fi_FI.ISO8859-15', + 'fi_fi.88591': 'fi_FI.ISO8859-1', + 'fi_fi.iso88591': 'fi_FI.ISO8859-1', + 'fi_fi.iso885915': 'fi_FI.ISO8859-15', + 'fi_fi.iso885915@euro': 'fi_FI.ISO8859-15', + 'fi_fi.utf8@euro': 'fi_FI.UTF-8', + 'fi_fi@euro': 'fi_FI.ISO8859-15', + 'finnish': 'fi_FI.ISO8859-1', + 'finnish.iso88591': 'fi_FI.ISO8859-1', + 'fo': 'fo_FO.ISO8859-1', + 'fo_fo': 'fo_FO.ISO8859-1', + 'fo_fo.iso88591': 'fo_FO.ISO8859-1', + 'fo_fo.iso885915': 'fo_FO.ISO8859-15', + 'fo_fo@euro': 'fo_FO.ISO8859-15', + 'fr': 'fr_FR.ISO8859-1', + 'fr.iso885915': 'fr_FR.ISO8859-15', + 'fr_be': 'fr_BE.ISO8859-1', + 'fr_be.88591': 'fr_BE.ISO8859-1', + 'fr_be.iso88591': 'fr_BE.ISO8859-1', + 'fr_be.iso885915': 'fr_BE.ISO8859-15', + 'fr_be.iso885915@euro': 'fr_BE.ISO8859-15', + 'fr_be.utf8@euro': 'fr_BE.UTF-8', + 'fr_be@euro': 'fr_BE.ISO8859-15', + 'fr_ca': 'fr_CA.ISO8859-1', + 'fr_ca.88591': 'fr_CA.ISO8859-1', + 'fr_ca.iso88591': 'fr_CA.ISO8859-1', + 'fr_ca.iso885915': 'fr_CA.ISO8859-15', + 'fr_ca@euro': 'fr_CA.ISO8859-15', + 'fr_ch': 'fr_CH.ISO8859-1', + 'fr_ch.88591': 'fr_CH.ISO8859-1', + 'fr_ch.iso88591': 'fr_CH.ISO8859-1', + 'fr_ch.iso885915': 'fr_CH.ISO8859-15', + 'fr_ch@euro': 'fr_CH.ISO8859-15', + 'fr_fr': 'fr_FR.ISO8859-1', + 'fr_fr.88591': 'fr_FR.ISO8859-1', + 'fr_fr.iso88591': 'fr_FR.ISO8859-1', + 'fr_fr.iso885915': 'fr_FR.ISO8859-15', + 'fr_fr.iso885915@euro': 'fr_FR.ISO8859-15', + 'fr_fr.utf8@euro': 'fr_FR.UTF-8', + 'fr_fr@euro': 'fr_FR.ISO8859-15', + 'fr_lu': 'fr_LU.ISO8859-1', + 'fr_lu.88591': 'fr_LU.ISO8859-1', + 'fr_lu.iso88591': 'fr_LU.ISO8859-1', + 'fr_lu.iso885915': 'fr_LU.ISO8859-15', + 'fr_lu.iso885915@euro': 'fr_LU.ISO8859-15', + 'fr_lu.utf8@euro': 'fr_LU.UTF-8', + 'fr_lu@euro': 'fr_LU.ISO8859-15', + 'fran\xe7ais': 'fr_FR.ISO8859-1', + 'fre_fr': 'fr_FR.ISO8859-1', + 'fre_fr.8859': 'fr_FR.ISO8859-1', + 'french': 'fr_FR.ISO8859-1', + 'french.iso88591': 'fr_CH.ISO8859-1', + 'french_france': 'fr_FR.ISO8859-1', + 'french_france.8859': 'fr_FR.ISO8859-1', + 'ga': 'ga_IE.ISO8859-1', + 'ga_ie': 'ga_IE.ISO8859-1', + 'ga_ie.iso88591': 'ga_IE.ISO8859-1', + 'ga_ie.iso885914': 'ga_IE.ISO8859-14', + 'ga_ie.iso885915': 'ga_IE.ISO8859-15', + 'ga_ie.iso885915@euro': 'ga_IE.ISO8859-15', + 'ga_ie.utf8@euro': 'ga_IE.UTF-8', + 'ga_ie@euro': 'ga_IE.ISO8859-15', + 'galego': 'gl_ES.ISO8859-1', + 'galician': 'gl_ES.ISO8859-1', + 'gd': 'gd_GB.ISO8859-1', + 'gd_gb': 'gd_GB.ISO8859-1', + 'gd_gb.iso88591': 'gd_GB.ISO8859-1', + 'gd_gb.iso885914': 'gd_GB.ISO8859-14', + 'gd_gb.iso885915': 'gd_GB.ISO8859-15', + 'gd_gb@euro': 'gd_GB.ISO8859-15', + 'ger_de': 'de_DE.ISO8859-1', + 'ger_de.8859': 'de_DE.ISO8859-1', + 'german': 'de_DE.ISO8859-1', + 'german.iso88591': 'de_CH.ISO8859-1', + 'german_germany': 'de_DE.ISO8859-1', + 'german_germany.8859': 'de_DE.ISO8859-1', + 'gl': 'gl_ES.ISO8859-1', + 'gl_es': 'gl_ES.ISO8859-1', + 'gl_es.iso88591': 'gl_ES.ISO8859-1', + 'gl_es.iso885915': 'gl_ES.ISO8859-15', + 'gl_es.iso885915@euro': 'gl_ES.ISO8859-15', + 'gl_es.utf8@euro': 'gl_ES.UTF-8', + 'gl_es@euro': 'gl_ES.ISO8859-15', + 'greek': 'el_GR.ISO8859-7', + 'greek.iso88597': 'el_GR.ISO8859-7', + 'gu_in': 'gu_IN.UTF-8', + 'gv': 'gv_GB.ISO8859-1', + 'gv_gb': 'gv_GB.ISO8859-1', + 'gv_gb.iso88591': 'gv_GB.ISO8859-1', + 'gv_gb.iso885914': 'gv_GB.ISO8859-14', + 'gv_gb.iso885915': 'gv_GB.ISO8859-15', + 'gv_gb@euro': 'gv_GB.ISO8859-15', + 'he': 'he_IL.ISO8859-8', + 'he_il': 'he_IL.ISO8859-8', + 'he_il.cp1255': 'he_IL.CP1255', + 'he_il.iso88598': 'he_IL.ISO8859-8', + 'he_il.microsoftcp1255': 'he_IL.CP1255', + 'hebrew': 'iw_IL.ISO8859-8', + 'hebrew.iso88598': 'iw_IL.ISO8859-8', + 'hi': 'hi_IN.ISCII-DEV', + 'hi_in': 'hi_IN.ISCII-DEV', + 'hi_in.isciidev': 'hi_IN.ISCII-DEV', + 'hne': 'hne_IN.UTF-8', + 'hr': 'hr_HR.ISO8859-2', + 'hr_hr': 'hr_HR.ISO8859-2', + 'hr_hr.iso88592': 'hr_HR.ISO8859-2', + 'hrvatski': 'hr_HR.ISO8859-2', + 'hu': 'hu_HU.ISO8859-2', + 'hu_hu': 'hu_HU.ISO8859-2', + 'hu_hu.iso88592': 'hu_HU.ISO8859-2', + 'hungarian': 'hu_HU.ISO8859-2', + 'icelandic': 'is_IS.ISO8859-1', + 'icelandic.iso88591': 'is_IS.ISO8859-1', + 'id': 'id_ID.ISO8859-1', + 'id_id': 'id_ID.ISO8859-1', + 'in': 'id_ID.ISO8859-1', + 'in_id': 'id_ID.ISO8859-1', + 'is': 'is_IS.ISO8859-1', + 'is_is': 'is_IS.ISO8859-1', + 'is_is.iso88591': 'is_IS.ISO8859-1', + 'is_is.iso885915': 'is_IS.ISO8859-15', + 'is_is@euro': 'is_IS.ISO8859-15', + 'iso-8859-1': 'en_US.ISO8859-1', + 'iso-8859-15': 'en_US.ISO8859-15', + 'iso8859-1': 'en_US.ISO8859-1', + 'iso8859-15': 'en_US.ISO8859-15', + 'iso_8859_1': 'en_US.ISO8859-1', + 'iso_8859_15': 'en_US.ISO8859-15', + 'it': 'it_IT.ISO8859-1', + 'it.iso885915': 'it_IT.ISO8859-15', + 'it_ch': 'it_CH.ISO8859-1', + 'it_ch.iso88591': 'it_CH.ISO8859-1', + 'it_ch.iso885915': 'it_CH.ISO8859-15', + 'it_ch@euro': 'it_CH.ISO8859-15', + 'it_it': 'it_IT.ISO8859-1', + 'it_it.88591': 'it_IT.ISO8859-1', + 'it_it.iso88591': 'it_IT.ISO8859-1', + 'it_it.iso885915': 'it_IT.ISO8859-15', + 'it_it.iso885915@euro': 'it_IT.ISO8859-15', + 'it_it.utf8@euro': 'it_IT.UTF-8', + 'it_it@euro': 'it_IT.ISO8859-15', + 'italian': 'it_IT.ISO8859-1', + 'italian.iso88591': 'it_IT.ISO8859-1', + 'iu': 'iu_CA.NUNACOM-8', + 'iu_ca': 'iu_CA.NUNACOM-8', + 'iu_ca.nunacom8': 'iu_CA.NUNACOM-8', + 'iw': 'he_IL.ISO8859-8', + 'iw_il': 'he_IL.ISO8859-8', + 'iw_il.iso88598': 'he_IL.ISO8859-8', + 'ja': 'ja_JP.eucJP', + 'ja.jis': 'ja_JP.JIS7', + 'ja.sjis': 'ja_JP.SJIS', + 'ja_jp': 'ja_JP.eucJP', + 'ja_jp.ajec': 'ja_JP.eucJP', + 'ja_jp.euc': 'ja_JP.eucJP', + 'ja_jp.eucjp': 'ja_JP.eucJP', + 'ja_jp.iso-2022-jp': 'ja_JP.JIS7', + 'ja_jp.iso2022jp': 'ja_JP.JIS7', + 'ja_jp.jis': 'ja_JP.JIS7', + 'ja_jp.jis7': 'ja_JP.JIS7', + 'ja_jp.mscode': 'ja_JP.SJIS', + 'ja_jp.pck': 'ja_JP.SJIS', + 'ja_jp.sjis': 'ja_JP.SJIS', + 'ja_jp.ujis': 'ja_JP.eucJP', + 'japan': 'ja_JP.eucJP', + 'japanese': 'ja_JP.eucJP', + 'japanese-euc': 'ja_JP.eucJP', + 'japanese.euc': 'ja_JP.eucJP', + 'japanese.sjis': 'ja_JP.SJIS', + 'jp_jp': 'ja_JP.eucJP', + 'ka': 'ka_GE.GEORGIAN-ACADEMY', + 'ka_ge': 'ka_GE.GEORGIAN-ACADEMY', + 'ka_ge.georgianacademy': 'ka_GE.GEORGIAN-ACADEMY', + 'ka_ge.georgianps': 'ka_GE.GEORGIAN-PS', + 'ka_ge.georgianrs': 'ka_GE.GEORGIAN-ACADEMY', + 'kl': 'kl_GL.ISO8859-1', + 'kl_gl': 'kl_GL.ISO8859-1', + 'kl_gl.iso88591': 'kl_GL.ISO8859-1', + 'kl_gl.iso885915': 'kl_GL.ISO8859-15', + 'kl_gl@euro': 'kl_GL.ISO8859-15', + 'km_kh': 'km_KH.UTF-8', + 'kn': 'kn_IN.UTF-8', + 'kn_in': 'kn_IN.UTF-8', + 'ko': 'ko_KR.eucKR', + 'ko_kr': 'ko_KR.eucKR', + 'ko_kr.euc': 'ko_KR.eucKR', + 'ko_kr.euckr': 'ko_KR.eucKR', + 'korean': 'ko_KR.eucKR', + 'korean.euc': 'ko_KR.eucKR', + 'ks': 'ks_IN.UTF-8', + 'ks_in@devanagari': 'ks_IN@devanagari.UTF-8', + 'kw': 'kw_GB.ISO8859-1', + 'kw_gb': 'kw_GB.ISO8859-1', + 'kw_gb.iso88591': 'kw_GB.ISO8859-1', + 'kw_gb.iso885914': 'kw_GB.ISO8859-14', + 'kw_gb.iso885915': 'kw_GB.ISO8859-15', + 'kw_gb@euro': 'kw_GB.ISO8859-15', + 'ky': 'ky_KG.UTF-8', + 'ky_kg': 'ky_KG.UTF-8', + 'lithuanian': 'lt_LT.ISO8859-13', + 'lo': 'lo_LA.MULELAO-1', + 'lo_la': 'lo_LA.MULELAO-1', + 'lo_la.cp1133': 'lo_LA.IBM-CP1133', + 'lo_la.ibmcp1133': 'lo_LA.IBM-CP1133', + 'lo_la.mulelao1': 'lo_LA.MULELAO-1', + 'lt': 'lt_LT.ISO8859-13', + 'lt_lt': 'lt_LT.ISO8859-13', + 'lt_lt.iso885913': 'lt_LT.ISO8859-13', + 'lt_lt.iso88594': 'lt_LT.ISO8859-4', + 'lv': 'lv_LV.ISO8859-13', + 'lv_lv': 'lv_LV.ISO8859-13', + 'lv_lv.iso885913': 'lv_LV.ISO8859-13', + 'lv_lv.iso88594': 'lv_LV.ISO8859-4', + 'mai': 'mai_IN.UTF-8', + 'mi': 'mi_NZ.ISO8859-1', + 'mi_nz': 'mi_NZ.ISO8859-1', + 'mi_nz.iso88591': 'mi_NZ.ISO8859-1', + 'mk': 'mk_MK.ISO8859-5', + 'mk_mk': 'mk_MK.ISO8859-5', + 'mk_mk.cp1251': 'mk_MK.CP1251', + 'mk_mk.iso88595': 'mk_MK.ISO8859-5', + 'mk_mk.microsoftcp1251': 'mk_MK.CP1251', + 'ml': 'ml_IN.UTF-8', + 'mr': 'mr_IN.UTF-8', + 'mr_in': 'mr_IN.UTF-8', + 'ms': 'ms_MY.ISO8859-1', + 'ms_my': 'ms_MY.ISO8859-1', + 'ms_my.iso88591': 'ms_MY.ISO8859-1', + 'mt': 'mt_MT.ISO8859-3', + 'mt_mt': 'mt_MT.ISO8859-3', + 'mt_mt.iso88593': 'mt_MT.ISO8859-3', + 'nb': 'nb_NO.ISO8859-1', + 'nb_no': 'nb_NO.ISO8859-1', + 'nb_no.88591': 'nb_NO.ISO8859-1', + 'nb_no.iso88591': 'nb_NO.ISO8859-1', + 'nb_no.iso885915': 'nb_NO.ISO8859-15', + 'nb_no@euro': 'nb_NO.ISO8859-15', + 'nl': 'nl_NL.ISO8859-1', + 'nl.iso885915': 'nl_NL.ISO8859-15', + 'nl_be': 'nl_BE.ISO8859-1', + 'nl_be.88591': 'nl_BE.ISO8859-1', + 'nl_be.iso88591': 'nl_BE.ISO8859-1', + 'nl_be.iso885915': 'nl_BE.ISO8859-15', + 'nl_be.iso885915@euro': 'nl_BE.ISO8859-15', + 'nl_be.utf8@euro': 'nl_BE.UTF-8', + 'nl_be@euro': 'nl_BE.ISO8859-15', + 'nl_nl': 'nl_NL.ISO8859-1', + 'nl_nl.88591': 'nl_NL.ISO8859-1', + 'nl_nl.iso88591': 'nl_NL.ISO8859-1', + 'nl_nl.iso885915': 'nl_NL.ISO8859-15', + 'nl_nl.iso885915@euro': 'nl_NL.ISO8859-15', + 'nl_nl.utf8@euro': 'nl_NL.UTF-8', + 'nl_nl@euro': 'nl_NL.ISO8859-15', + 'nn': 'nn_NO.ISO8859-1', + 'nn_no': 'nn_NO.ISO8859-1', + 'nn_no.88591': 'nn_NO.ISO8859-1', + 'nn_no.iso88591': 'nn_NO.ISO8859-1', + 'nn_no.iso885915': 'nn_NO.ISO8859-15', + 'nn_no@euro': 'nn_NO.ISO8859-15', + 'no': 'no_NO.ISO8859-1', + 'no@nynorsk': 'ny_NO.ISO8859-1', + 'no_no': 'no_NO.ISO8859-1', + 'no_no.88591': 'no_NO.ISO8859-1', + 'no_no.iso88591': 'no_NO.ISO8859-1', + 'no_no.iso885915': 'no_NO.ISO8859-15', + 'no_no.iso88591@bokmal': 'no_NO.ISO8859-1', + 'no_no.iso88591@nynorsk': 'no_NO.ISO8859-1', + 'no_no@euro': 'no_NO.ISO8859-15', + 'norwegian': 'no_NO.ISO8859-1', + 'norwegian.iso88591': 'no_NO.ISO8859-1', + 'nr': 'nr_ZA.ISO8859-1', + 'nr_za': 'nr_ZA.ISO8859-1', + 'nr_za.iso88591': 'nr_ZA.ISO8859-1', + 'nso': 'nso_ZA.ISO8859-15', + 'nso_za': 'nso_ZA.ISO8859-15', + 'nso_za.iso885915': 'nso_ZA.ISO8859-15', + 'ny': 'ny_NO.ISO8859-1', + 'ny_no': 'ny_NO.ISO8859-1', + 'ny_no.88591': 'ny_NO.ISO8859-1', + 'ny_no.iso88591': 'ny_NO.ISO8859-1', + 'ny_no.iso885915': 'ny_NO.ISO8859-15', + 'ny_no@euro': 'ny_NO.ISO8859-15', + 'nynorsk': 'nn_NO.ISO8859-1', + 'oc': 'oc_FR.ISO8859-1', + 'oc_fr': 'oc_FR.ISO8859-1', + 'oc_fr.iso88591': 'oc_FR.ISO8859-1', + 'oc_fr.iso885915': 'oc_FR.ISO8859-15', + 'oc_fr@euro': 'oc_FR.ISO8859-15', + 'or': 'or_IN.UTF-8', + 'pa': 'pa_IN.UTF-8', + 'pa_in': 'pa_IN.UTF-8', + 'pd': 'pd_US.ISO8859-1', + 'pd_de': 'pd_DE.ISO8859-1', + 'pd_de.iso88591': 'pd_DE.ISO8859-1', + 'pd_de.iso885915': 'pd_DE.ISO8859-15', + 'pd_de@euro': 'pd_DE.ISO8859-15', + 'pd_us': 'pd_US.ISO8859-1', + 'pd_us.iso88591': 'pd_US.ISO8859-1', + 'pd_us.iso885915': 'pd_US.ISO8859-15', + 'pd_us@euro': 'pd_US.ISO8859-15', + 'ph': 'ph_PH.ISO8859-1', + 'ph_ph': 'ph_PH.ISO8859-1', + 'ph_ph.iso88591': 'ph_PH.ISO8859-1', + 'pl': 'pl_PL.ISO8859-2', + 'pl_pl': 'pl_PL.ISO8859-2', + 'pl_pl.iso88592': 'pl_PL.ISO8859-2', + 'polish': 'pl_PL.ISO8859-2', + 'portuguese': 'pt_PT.ISO8859-1', + 'portuguese.iso88591': 'pt_PT.ISO8859-1', + 'portuguese_brazil': 'pt_BR.ISO8859-1', + 'portuguese_brazil.8859': 'pt_BR.ISO8859-1', + 'posix': 'C', + 'posix-utf2': 'C', + 'pp': 'pp_AN.ISO8859-1', + 'pp_an': 'pp_AN.ISO8859-1', + 'pp_an.iso88591': 'pp_AN.ISO8859-1', + 'pt': 'pt_PT.ISO8859-1', + 'pt.iso885915': 'pt_PT.ISO8859-15', + 'pt_br': 'pt_BR.ISO8859-1', + 'pt_br.88591': 'pt_BR.ISO8859-1', + 'pt_br.iso88591': 'pt_BR.ISO8859-1', + 'pt_br.iso885915': 'pt_BR.ISO8859-15', + 'pt_br@euro': 'pt_BR.ISO8859-15', + 'pt_pt': 'pt_PT.ISO8859-1', + 'pt_pt.88591': 'pt_PT.ISO8859-1', + 'pt_pt.iso88591': 'pt_PT.ISO8859-1', + 'pt_pt.iso885915': 'pt_PT.ISO8859-15', + 'pt_pt.iso885915@euro': 'pt_PT.ISO8859-15', + 'pt_pt.utf8@euro': 'pt_PT.UTF-8', + 'pt_pt@euro': 'pt_PT.ISO8859-15', + 'ro': 'ro_RO.ISO8859-2', + 'ro_ro': 'ro_RO.ISO8859-2', + 'ro_ro.iso88592': 'ro_RO.ISO8859-2', + 'romanian': 'ro_RO.ISO8859-2', + 'ru': 'ru_RU.UTF-8', + 'ru.koi8r': 'ru_RU.KOI8-R', + 'ru_ru': 'ru_RU.UTF-8', + 'ru_ru.cp1251': 'ru_RU.CP1251', + 'ru_ru.iso88595': 'ru_RU.ISO8859-5', + 'ru_ru.koi8r': 'ru_RU.KOI8-R', + 'ru_ru.microsoftcp1251': 'ru_RU.CP1251', + 'ru_ua': 'ru_UA.KOI8-U', + 'ru_ua.cp1251': 'ru_UA.CP1251', + 'ru_ua.koi8u': 'ru_UA.KOI8-U', + 'ru_ua.microsoftcp1251': 'ru_UA.CP1251', + 'rumanian': 'ro_RO.ISO8859-2', + 'russian': 'ru_RU.ISO8859-5', + 'rw': 'rw_RW.ISO8859-1', + 'rw_rw': 'rw_RW.ISO8859-1', + 'rw_rw.iso88591': 'rw_RW.ISO8859-1', + 'sd': 'sd_IN@devanagari.UTF-8', + 'se_no': 'se_NO.UTF-8', + 'serbocroatian': 'sr_RS.UTF-8@latin', + 'sh': 'sr_RS.UTF-8@latin', + 'sh_ba.iso88592@bosnia': 'sr_CS.ISO8859-2', + 'sh_hr': 'sh_HR.ISO8859-2', + 'sh_hr.iso88592': 'hr_HR.ISO8859-2', + 'sh_sp': 'sr_CS.ISO8859-2', + 'sh_yu': 'sr_RS.UTF-8@latin', + 'si': 'si_LK.UTF-8', + 'si_lk': 'si_LK.UTF-8', + 'sinhala': 'si_LK.UTF-8', + 'sk': 'sk_SK.ISO8859-2', + 'sk_sk': 'sk_SK.ISO8859-2', + 'sk_sk.iso88592': 'sk_SK.ISO8859-2', + 'sl': 'sl_SI.ISO8859-2', + 'sl_cs': 'sl_CS.ISO8859-2', + 'sl_si': 'sl_SI.ISO8859-2', + 'sl_si.iso88592': 'sl_SI.ISO8859-2', + 'slovak': 'sk_SK.ISO8859-2', + 'slovene': 'sl_SI.ISO8859-2', + 'slovenian': 'sl_SI.ISO8859-2', + 'sp': 'sr_CS.ISO8859-5', + 'sp_yu': 'sr_CS.ISO8859-5', + 'spanish': 'es_ES.ISO8859-1', + 'spanish.iso88591': 'es_ES.ISO8859-1', + 'spanish_spain': 'es_ES.ISO8859-1', + 'spanish_spain.8859': 'es_ES.ISO8859-1', + 'sq': 'sq_AL.ISO8859-2', + 'sq_al': 'sq_AL.ISO8859-2', + 'sq_al.iso88592': 'sq_AL.ISO8859-2', + 'sr': 'sr_RS.UTF-8', + 'sr@cyrillic': 'sr_RS.UTF-8', + 'sr@latin': 'sr_RS.UTF-8@latin', + 'sr@latn': 'sr_RS.UTF-8@latin', + 'sr_cs': 'sr_RS.UTF-8', + 'sr_cs.iso88592': 'sr_CS.ISO8859-2', + 'sr_cs.iso88592@latn': 'sr_CS.ISO8859-2', + 'sr_cs.iso88595': 'sr_CS.ISO8859-5', + 'sr_cs.utf8@latn': 'sr_RS.UTF-8@latin', + 'sr_cs@latn': 'sr_RS.UTF-8@latin', + 'sr_me': 'sr_ME.UTF-8', + 'sr_rs': 'sr_RS.UTF-8', + 'sr_rs.utf8@latn': 'sr_RS.UTF-8@latin', + 'sr_rs@latin': 'sr_RS.UTF-8@latin', + 'sr_rs@latn': 'sr_RS.UTF-8@latin', + 'sr_sp': 'sr_CS.ISO8859-2', + 'sr_yu': 'sr_RS.UTF-8@latin', + 'sr_yu.cp1251@cyrillic': 'sr_CS.CP1251', + 'sr_yu.iso88592': 'sr_CS.ISO8859-2', + 'sr_yu.iso88595': 'sr_CS.ISO8859-5', + 'sr_yu.iso88595@cyrillic': 'sr_CS.ISO8859-5', + 'sr_yu.microsoftcp1251@cyrillic': 'sr_CS.CP1251', + 'sr_yu.utf8@cyrillic': 'sr_RS.UTF-8', + 'sr_yu@cyrillic': 'sr_RS.UTF-8', + 'ss': 'ss_ZA.ISO8859-1', + 'ss_za': 'ss_ZA.ISO8859-1', + 'ss_za.iso88591': 'ss_ZA.ISO8859-1', + 'st': 'st_ZA.ISO8859-1', + 'st_za': 'st_ZA.ISO8859-1', + 'st_za.iso88591': 'st_ZA.ISO8859-1', + 'sv': 'sv_SE.ISO8859-1', + 'sv.iso885915': 'sv_SE.ISO8859-15', + 'sv_fi': 'sv_FI.ISO8859-1', + 'sv_fi.iso88591': 'sv_FI.ISO8859-1', + 'sv_fi.iso885915': 'sv_FI.ISO8859-15', + 'sv_fi.iso885915@euro': 'sv_FI.ISO8859-15', + 'sv_fi.utf8@euro': 'sv_FI.UTF-8', + 'sv_fi@euro': 'sv_FI.ISO8859-15', + 'sv_se': 'sv_SE.ISO8859-1', + 'sv_se.88591': 'sv_SE.ISO8859-1', + 'sv_se.iso88591': 'sv_SE.ISO8859-1', + 'sv_se.iso885915': 'sv_SE.ISO8859-15', + 'sv_se@euro': 'sv_SE.ISO8859-15', + 'swedish': 'sv_SE.ISO8859-1', + 'swedish.iso88591': 'sv_SE.ISO8859-1', + 'ta': 'ta_IN.TSCII-0', + 'ta_in': 'ta_IN.TSCII-0', + 'ta_in.tscii': 'ta_IN.TSCII-0', + 'ta_in.tscii0': 'ta_IN.TSCII-0', + 'te': 'te_IN.UTF-8', + 'tg': 'tg_TJ.KOI8-C', + 'tg_tj': 'tg_TJ.KOI8-C', + 'tg_tj.koi8c': 'tg_TJ.KOI8-C', + 'th': 'th_TH.ISO8859-11', + 'th_th': 'th_TH.ISO8859-11', + 'th_th.iso885911': 'th_TH.ISO8859-11', + 'th_th.tactis': 'th_TH.TIS620', + 'th_th.tis620': 'th_TH.TIS620', + 'thai': 'th_TH.ISO8859-11', + 'tl': 'tl_PH.ISO8859-1', + 'tl_ph': 'tl_PH.ISO8859-1', + 'tl_ph.iso88591': 'tl_PH.ISO8859-1', + 'tn': 'tn_ZA.ISO8859-15', + 'tn_za': 'tn_ZA.ISO8859-15', + 'tn_za.iso885915': 'tn_ZA.ISO8859-15', + 'tr': 'tr_TR.ISO8859-9', + 'tr_tr': 'tr_TR.ISO8859-9', + 'tr_tr.iso88599': 'tr_TR.ISO8859-9', + 'ts': 'ts_ZA.ISO8859-1', + 'ts_za': 'ts_ZA.ISO8859-1', + 'ts_za.iso88591': 'ts_ZA.ISO8859-1', + 'tt': 'tt_RU.TATAR-CYR', + 'tt_ru': 'tt_RU.TATAR-CYR', + 'tt_ru.koi8c': 'tt_RU.KOI8-C', + 'tt_ru.tatarcyr': 'tt_RU.TATAR-CYR', + 'turkish': 'tr_TR.ISO8859-9', + 'turkish.iso88599': 'tr_TR.ISO8859-9', + 'uk': 'uk_UA.KOI8-U', + 'uk_ua': 'uk_UA.KOI8-U', + 'uk_ua.cp1251': 'uk_UA.CP1251', + 'uk_ua.iso88595': 'uk_UA.ISO8859-5', + 'uk_ua.koi8u': 'uk_UA.KOI8-U', + 'uk_ua.microsoftcp1251': 'uk_UA.CP1251', + 'univ': 'en_US.utf', + 'universal': 'en_US.utf', + 'universal.utf8@ucs4': 'en_US.UTF-8', + 'ur': 'ur_PK.CP1256', + 'ur_pk': 'ur_PK.CP1256', + 'ur_pk.cp1256': 'ur_PK.CP1256', + 'ur_pk.microsoftcp1256': 'ur_PK.CP1256', + 'uz': 'uz_UZ.UTF-8', + 'uz_uz': 'uz_UZ.UTF-8', + 'uz_uz.iso88591': 'uz_UZ.ISO8859-1', + 'uz_uz.utf8@cyrillic': 'uz_UZ.UTF-8', + 'uz_uz@cyrillic': 'uz_UZ.UTF-8', + 've': 've_ZA.UTF-8', + 've_za': 've_ZA.UTF-8', + 'vi': 'vi_VN.TCVN', + 'vi_vn': 'vi_VN.TCVN', + 'vi_vn.tcvn': 'vi_VN.TCVN', + 'vi_vn.tcvn5712': 'vi_VN.TCVN', + 'vi_vn.viscii': 'vi_VN.VISCII', + 'vi_vn.viscii111': 'vi_VN.VISCII', + 'wa': 'wa_BE.ISO8859-1', + 'wa_be': 'wa_BE.ISO8859-1', + 'wa_be.iso88591': 'wa_BE.ISO8859-1', + 'wa_be.iso885915': 'wa_BE.ISO8859-15', + 'wa_be.iso885915@euro': 'wa_BE.ISO8859-15', + 'wa_be@euro': 'wa_BE.ISO8859-15', + 'xh': 'xh_ZA.ISO8859-1', + 'xh_za': 'xh_ZA.ISO8859-1', + 'xh_za.iso88591': 'xh_ZA.ISO8859-1', + 'yi': 'yi_US.CP1255', + 'yi_us': 'yi_US.CP1255', + 'yi_us.cp1255': 'yi_US.CP1255', + 'yi_us.microsoftcp1255': 'yi_US.CP1255', + 'zh': 'zh_CN.eucCN', + 'zh_cn': 'zh_CN.gb2312', + 'zh_cn.big5': 'zh_TW.big5', + 'zh_cn.euc': 'zh_CN.eucCN', + 'zh_cn.gb18030': 'zh_CN.gb18030', + 'zh_cn.gb2312': 'zh_CN.gb2312', + 'zh_cn.gbk': 'zh_CN.gbk', + 'zh_hk': 'zh_HK.big5hkscs', + 'zh_hk.big5': 'zh_HK.big5', + 'zh_hk.big5hk': 'zh_HK.big5hkscs', + 'zh_hk.big5hkscs': 'zh_HK.big5hkscs', + 'zh_tw': 'zh_TW.big5', + 'zh_tw.big5': 'zh_TW.big5', + 'zh_tw.euc': 'zh_TW.eucTW', + 'zh_tw.euctw': 'zh_TW.eucTW', + 'zu': 'zu_ZA.ISO8859-1', + 'zu_za': 'zu_ZA.ISO8859-1', + 'zu_za.iso88591': 'zu_ZA.ISO8859-1', +} + +# +# This maps Windows language identifiers to locale strings. +# +# This list has been updated from +# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_238z.asp +# to include every locale up to Windows Vista. +# +# NOTE: this mapping is incomplete. If your language is missing, please +# submit a bug report to the Python bug tracker at http://bugs.python.org/ +# Make sure you include the missing language identifier and the suggested +# locale code. +# + +windows_locale = { + 0x0436: "af_ZA", # Afrikaans + 0x041c: "sq_AL", # Albanian + 0x0484: "gsw_FR",# Alsatian - France + 0x045e: "am_ET", # Amharic - Ethiopia + 0x0401: "ar_SA", # Arabic - Saudi Arabia + 0x0801: "ar_IQ", # Arabic - Iraq + 0x0c01: "ar_EG", # Arabic - Egypt + 0x1001: "ar_LY", # Arabic - Libya + 0x1401: "ar_DZ", # Arabic - Algeria + 0x1801: "ar_MA", # Arabic - Morocco + 0x1c01: "ar_TN", # Arabic - Tunisia + 0x2001: "ar_OM", # Arabic - Oman + 0x2401: "ar_YE", # Arabic - Yemen + 0x2801: "ar_SY", # Arabic - Syria + 0x2c01: "ar_JO", # Arabic - Jordan + 0x3001: "ar_LB", # Arabic - Lebanon + 0x3401: "ar_KW", # Arabic - Kuwait + 0x3801: "ar_AE", # Arabic - United Arab Emirates + 0x3c01: "ar_BH", # Arabic - Bahrain + 0x4001: "ar_QA", # Arabic - Qatar + 0x042b: "hy_AM", # Armenian + 0x044d: "as_IN", # Assamese - India + 0x042c: "az_AZ", # Azeri - Latin + 0x082c: "az_AZ", # Azeri - Cyrillic + 0x046d: "ba_RU", # Bashkir + 0x042d: "eu_ES", # Basque - Russia + 0x0423: "be_BY", # Belarusian + 0x0445: "bn_IN", # Begali + 0x201a: "bs_BA", # Bosnian - Cyrillic + 0x141a: "bs_BA", # Bosnian - Latin + 0x047e: "br_FR", # Breton - France + 0x0402: "bg_BG", # Bulgarian +# 0x0455: "my_MM", # Burmese - Not supported + 0x0403: "ca_ES", # Catalan + 0x0004: "zh_CHS",# Chinese - Simplified + 0x0404: "zh_TW", # Chinese - Taiwan + 0x0804: "zh_CN", # Chinese - PRC + 0x0c04: "zh_HK", # Chinese - Hong Kong S.A.R. + 0x1004: "zh_SG", # Chinese - Singapore + 0x1404: "zh_MO", # Chinese - Macao S.A.R. + 0x7c04: "zh_CHT",# Chinese - Traditional + 0x0483: "co_FR", # Corsican - France + 0x041a: "hr_HR", # Croatian + 0x101a: "hr_BA", # Croatian - Bosnia + 0x0405: "cs_CZ", # Czech + 0x0406: "da_DK", # Danish + 0x048c: "gbz_AF",# Dari - Afghanistan + 0x0465: "div_MV",# Divehi - Maldives + 0x0413: "nl_NL", # Dutch - The Netherlands + 0x0813: "nl_BE", # Dutch - Belgium + 0x0409: "en_US", # English - United States + 0x0809: "en_GB", # English - United Kingdom + 0x0c09: "en_AU", # English - Australia + 0x1009: "en_CA", # English - Canada + 0x1409: "en_NZ", # English - New Zealand + 0x1809: "en_IE", # English - Ireland + 0x1c09: "en_ZA", # English - South Africa + 0x2009: "en_JA", # English - Jamaica + 0x2409: "en_CB", # English - Carribbean + 0x2809: "en_BZ", # English - Belize + 0x2c09: "en_TT", # English - Trinidad + 0x3009: "en_ZW", # English - Zimbabwe + 0x3409: "en_PH", # English - Philippines + 0x4009: "en_IN", # English - India + 0x4409: "en_MY", # English - Malaysia + 0x4809: "en_IN", # English - Singapore + 0x0425: "et_EE", # Estonian + 0x0438: "fo_FO", # Faroese + 0x0464: "fil_PH",# Filipino + 0x040b: "fi_FI", # Finnish + 0x040c: "fr_FR", # French - France + 0x080c: "fr_BE", # French - Belgium + 0x0c0c: "fr_CA", # French - Canada + 0x100c: "fr_CH", # French - Switzerland + 0x140c: "fr_LU", # French - Luxembourg + 0x180c: "fr_MC", # French - Monaco + 0x0462: "fy_NL", # Frisian - Netherlands + 0x0456: "gl_ES", # Galician + 0x0437: "ka_GE", # Georgian + 0x0407: "de_DE", # German - Germany + 0x0807: "de_CH", # German - Switzerland + 0x0c07: "de_AT", # German - Austria + 0x1007: "de_LU", # German - Luxembourg + 0x1407: "de_LI", # German - Liechtenstein + 0x0408: "el_GR", # Greek + 0x046f: "kl_GL", # Greenlandic - Greenland + 0x0447: "gu_IN", # Gujarati + 0x0468: "ha_NG", # Hausa - Latin + 0x040d: "he_IL", # Hebrew + 0x0439: "hi_IN", # Hindi + 0x040e: "hu_HU", # Hungarian + 0x040f: "is_IS", # Icelandic + 0x0421: "id_ID", # Indonesian + 0x045d: "iu_CA", # Inuktitut - Syllabics + 0x085d: "iu_CA", # Inuktitut - Latin + 0x083c: "ga_IE", # Irish - Ireland + 0x0410: "it_IT", # Italian - Italy + 0x0810: "it_CH", # Italian - Switzerland + 0x0411: "ja_JP", # Japanese + 0x044b: "kn_IN", # Kannada - India + 0x043f: "kk_KZ", # Kazakh + 0x0453: "kh_KH", # Khmer - Cambodia + 0x0486: "qut_GT",# K'iche - Guatemala + 0x0487: "rw_RW", # Kinyarwanda - Rwanda + 0x0457: "kok_IN",# Konkani + 0x0412: "ko_KR", # Korean + 0x0440: "ky_KG", # Kyrgyz + 0x0454: "lo_LA", # Lao - Lao PDR + 0x0426: "lv_LV", # Latvian + 0x0427: "lt_LT", # Lithuanian + 0x082e: "dsb_DE",# Lower Sorbian - Germany + 0x046e: "lb_LU", # Luxembourgish + 0x042f: "mk_MK", # FYROM Macedonian + 0x043e: "ms_MY", # Malay - Malaysia + 0x083e: "ms_BN", # Malay - Brunei Darussalam + 0x044c: "ml_IN", # Malayalam - India + 0x043a: "mt_MT", # Maltese + 0x0481: "mi_NZ", # Maori + 0x047a: "arn_CL",# Mapudungun + 0x044e: "mr_IN", # Marathi + 0x047c: "moh_CA",# Mohawk - Canada + 0x0450: "mn_MN", # Mongolian - Cyrillic + 0x0850: "mn_CN", # Mongolian - PRC + 0x0461: "ne_NP", # Nepali + 0x0414: "nb_NO", # Norwegian - Bokmal + 0x0814: "nn_NO", # Norwegian - Nynorsk + 0x0482: "oc_FR", # Occitan - France + 0x0448: "or_IN", # Oriya - India + 0x0463: "ps_AF", # Pashto - Afghanistan + 0x0429: "fa_IR", # Persian + 0x0415: "pl_PL", # Polish + 0x0416: "pt_BR", # Portuguese - Brazil + 0x0816: "pt_PT", # Portuguese - Portugal + 0x0446: "pa_IN", # Punjabi + 0x046b: "quz_BO",# Quechua (Bolivia) + 0x086b: "quz_EC",# Quechua (Ecuador) + 0x0c6b: "quz_PE",# Quechua (Peru) + 0x0418: "ro_RO", # Romanian - Romania + 0x0417: "rm_CH", # Romansh + 0x0419: "ru_RU", # Russian + 0x243b: "smn_FI",# Sami Finland + 0x103b: "smj_NO",# Sami Norway + 0x143b: "smj_SE",# Sami Sweden + 0x043b: "se_NO", # Sami Northern Norway + 0x083b: "se_SE", # Sami Northern Sweden + 0x0c3b: "se_FI", # Sami Northern Finland + 0x203b: "sms_FI",# Sami Skolt + 0x183b: "sma_NO",# Sami Southern Norway + 0x1c3b: "sma_SE",# Sami Southern Sweden + 0x044f: "sa_IN", # Sanskrit + 0x0c1a: "sr_SP", # Serbian - Cyrillic + 0x1c1a: "sr_BA", # Serbian - Bosnia Cyrillic + 0x081a: "sr_SP", # Serbian - Latin + 0x181a: "sr_BA", # Serbian - Bosnia Latin + 0x045b: "si_LK", # Sinhala - Sri Lanka + 0x046c: "ns_ZA", # Northern Sotho + 0x0432: "tn_ZA", # Setswana - Southern Africa + 0x041b: "sk_SK", # Slovak + 0x0424: "sl_SI", # Slovenian + 0x040a: "es_ES", # Spanish - Spain + 0x080a: "es_MX", # Spanish - Mexico + 0x0c0a: "es_ES", # Spanish - Spain (Modern) + 0x100a: "es_GT", # Spanish - Guatemala + 0x140a: "es_CR", # Spanish - Costa Rica + 0x180a: "es_PA", # Spanish - Panama + 0x1c0a: "es_DO", # Spanish - Dominican Republic + 0x200a: "es_VE", # Spanish - Venezuela + 0x240a: "es_CO", # Spanish - Colombia + 0x280a: "es_PE", # Spanish - Peru + 0x2c0a: "es_AR", # Spanish - Argentina + 0x300a: "es_EC", # Spanish - Ecuador + 0x340a: "es_CL", # Spanish - Chile + 0x380a: "es_UR", # Spanish - Uruguay + 0x3c0a: "es_PY", # Spanish - Paraguay + 0x400a: "es_BO", # Spanish - Bolivia + 0x440a: "es_SV", # Spanish - El Salvador + 0x480a: "es_HN", # Spanish - Honduras + 0x4c0a: "es_NI", # Spanish - Nicaragua + 0x500a: "es_PR", # Spanish - Puerto Rico + 0x540a: "es_US", # Spanish - United States +# 0x0430: "", # Sutu - Not supported + 0x0441: "sw_KE", # Swahili + 0x041d: "sv_SE", # Swedish - Sweden + 0x081d: "sv_FI", # Swedish - Finland + 0x045a: "syr_SY",# Syriac + 0x0428: "tg_TJ", # Tajik - Cyrillic + 0x085f: "tmz_DZ",# Tamazight - Latin + 0x0449: "ta_IN", # Tamil + 0x0444: "tt_RU", # Tatar + 0x044a: "te_IN", # Telugu + 0x041e: "th_TH", # Thai + 0x0851: "bo_BT", # Tibetan - Bhutan + 0x0451: "bo_CN", # Tibetan - PRC + 0x041f: "tr_TR", # Turkish + 0x0442: "tk_TM", # Turkmen - Cyrillic + 0x0480: "ug_CN", # Uighur - Arabic + 0x0422: "uk_UA", # Ukrainian + 0x042e: "wen_DE",# Upper Sorbian - Germany + 0x0420: "ur_PK", # Urdu + 0x0820: "ur_IN", # Urdu - India + 0x0443: "uz_UZ", # Uzbek - Latin + 0x0843: "uz_UZ", # Uzbek - Cyrillic + 0x042a: "vi_VN", # Vietnamese + 0x0452: "cy_GB", # Welsh + 0x0488: "wo_SN", # Wolof - Senegal + 0x0434: "xh_ZA", # Xhosa - South Africa + 0x0485: "sah_RU",# Yakut - Cyrillic + 0x0478: "ii_CN", # Yi - PRC + 0x046a: "yo_NG", # Yoruba - Nigeria + 0x0435: "zu_ZA", # Zulu +} + +def _print_locale(): + + """ Test function. + """ + categories = {} + def _init_categories(categories=categories): + for k,v in globals().items(): + if k[:3] == 'LC_': + categories[k] = v + _init_categories() + del categories['LC_ALL'] + + print 'Locale defaults as determined by getdefaultlocale():' + print '-'*72 + lang, enc = getdefaultlocale() + print 'Language: ', lang or '(undefined)' + print 'Encoding: ', enc or '(undefined)' + print + + print 'Locale settings on startup:' + print '-'*72 + for name,category in categories.items(): + print name, '...' + lang, enc = getlocale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print + + print + print 'Locale settings after calling resetlocale():' + print '-'*72 + resetlocale() + for name,category in categories.items(): + print name, '...' + lang, enc = getlocale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print + + try: + setlocale(LC_ALL, "") + except: + print 'NOTE:' + print 'setlocale(LC_ALL, "") does not support the default locale' + print 'given in the OS environment variables.' + else: + print + print 'Locale settings after calling setlocale(LC_ALL, ""):' + print '-'*72 + for name,category in categories.items(): + print name, '...' + lang, enc = getlocale(category) + print ' Language: ', lang or '(undefined)' + print ' Encoding: ', enc or '(undefined)' + print + +### + +try: + LC_MESSAGES +except NameError: + pass +else: + __all__.append("LC_MESSAGES") + +if __name__=='__main__': + print 'Locale aliasing:' + print + _print_locale() + print + print 'Number formatting:' + print + _test() diff --git a/Lib/ntpath.py b/Lib/ntpath.py deleted file mode 100644 index 934663505..000000000 --- a/Lib/ntpath.py +++ /dev/null @@ -1,560 +0,0 @@ -# Module 'ntpath' -- common operations on WinNT/Win95 pathnames -"""Common pathname manipulations, WindowsNT/95 version. - -Instead of importing this module directly, import os and refer to this -module as os.path. -""" - -import os -import sys -import stat -import genericpath -import warnings - -from genericpath import * - -__all__ = ["normcase","isabs","join","splitdrive","split","splitext", - "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","lexists","isdir","isfile", - "ismount","walk","expanduser","expandvars","normpath","abspath", - "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", - "extsep","devnull","realpath","supports_unicode_filenames","relpath"] - -# strings representing various path-related bits and pieces -curdir = '.' -pardir = '..' -extsep = '.' -sep = '\\' -pathsep = ';' -altsep = '/' -defpath = '.;C:\\bin' -if 'ce' in sys.builtin_module_names: - defpath = '\\Windows' -elif 'os2' in sys.builtin_module_names: - # OS/2 w/ VACPP - altsep = '/' -devnull = 'nul' - -# Normalize the case of a pathname and map slashes to backslashes. -# Other normalizations (such as optimizing '../' away) are not done -# (this is done by normpath). - -def normcase(s): - """Normalize case of pathname. - - Makes all characters lowercase and all slashes into backslashes.""" - return s.replace("/", "\\").lower() - - -# Return whether a path is absolute. -# Trivial in Posix, harder on the Mac or MS-DOS. -# For DOS it is absolute if it starts with a slash or backslash (current -# volume), or if a pathname after the volume letter and colon / UNC resource -# starts with a slash or backslash. - -def isabs(s): - """Test whether a path is absolute""" - s = splitdrive(s)[1] - return s != '' and s[:1] in '/\\' - - -# Join two (or more) paths. - -def join(a, *p): - """Join two or more pathname components, inserting "\\" as needed. - If any component is an absolute path, all previous path components - will be discarded.""" - path = a - for b in p: - b_wins = 0 # set to 1 iff b makes path irrelevant - if path == "": - b_wins = 1 - - elif isabs(b): - # This probably wipes out path so far. However, it's more - # complicated if path begins with a drive letter: - # 1. join('c:', '/a') == 'c:/a' - # 2. join('c:/', '/a') == 'c:/a' - # But - # 3. join('c:/a', '/b') == '/b' - # 4. join('c:', 'd:/') = 'd:/' - # 5. join('c:/', 'd:/') = 'd:/' - if path[1:2] != ":" or b[1:2] == ":": - # Path doesn't start with a drive letter, or cases 4 and 5. - b_wins = 1 - - # Else path has a drive letter, and b doesn't but is absolute. - elif len(path) > 3 or (len(path) == 3 and - path[-1] not in "/\\"): - # case 3 - b_wins = 1 - - if b_wins: - path = b - else: - # Join, and ensure there's a separator. - assert len(path) > 0 - if path[-1] in "/\\": - if b and b[0] in "/\\": - path += b[1:] - else: - path += b - elif path[-1] == ":": - path += b - elif b: - if b[0] in "/\\": - path += b - else: - path += "\\" + b - else: - # path is not empty and does not end with a backslash, - # but b is empty; since, e.g., split('a/') produces - # ('a', ''), it's best if join() adds a backslash in - # this case. - path += '\\' - - return path - - -# Split a path in a drive specification (a drive letter followed by a -# colon) and the path specification. -# It is always true that drivespec + pathspec == p -def splitdrive(p): - """Split a pathname into drive and path specifiers. Returns a 2-tuple -"(drive,path)"; either part may be empty""" - if p[1:2] == ':': - return p[0:2], p[2:] - return '', p - - -# Parse UNC paths -def splitunc(p): - """Split a pathname into UNC mount point and relative path specifiers. - - Return a 2-tuple (unc, rest); either part may be empty. - If unc is not empty, it has the form '//host/mount' (or similar - using backslashes). unc+rest is always the input path. - Paths containing drive letters never have an UNC part. - """ - if p[1:2] == ':': - return '', p # Drive letter present - firstTwo = p[0:2] - if firstTwo == '//' or firstTwo == '\\\\': - # is a UNC path: - # vvvvvvvvvvvvvvvvvvvv equivalent to drive letter - # \\machine\mountpoint\directories... - # directory ^^^^^^^^^^^^^^^ - normp = normcase(p) - index = normp.find('\\', 2) - if index == -1: - ##raise RuntimeError, 'illegal UNC path: "' + p + '"' - return ("", p) - index = normp.find('\\', index + 1) - if index == -1: - index = len(p) - return p[:index], p[index:] - return '', p - - -# Split a path in head (everything up to the last '/') and tail (the -# rest). After the trailing '/' is stripped, the invariant -# join(head, tail) == p holds. -# The resulting head won't end in '/' unless it is the root. - -def split(p): - """Split a pathname. - - Return tuple (head, tail) where tail is everything after the final slash. - Either part may be empty.""" - - d, p = splitdrive(p) - # set i to index beyond p's last slash - i = len(p) - while i and p[i-1] not in '/\\': - i = i - 1 - head, tail = p[:i], p[i:] # now tail has no slashes - # remove trailing slashes from head, unless it's all slashes - head2 = head - while head2 and head2[-1] in '/\\': - head2 = head2[:-1] - head = head2 or head - return d + head, tail - - -# Split a path in root and extension. -# The extension is everything starting at the last dot in the last -# pathname component; the root is everything before that. -# It is always true that root + ext == p. - -def splitext(p): - return genericpath._splitext(p, sep, altsep, extsep) -splitext.__doc__ = genericpath._splitext.__doc__ - - -# Return the tail (basename) part of a path. - -def basename(p): - """Returns the final component of a pathname""" - return split(p)[1] - - -# Return the head (dirname) part of a path. - -def dirname(p): - """Returns the directory component of a pathname""" - return split(p)[0] - -# Is a path a symbolic link? -# This will always return false on systems where posix.lstat doesn't exist. - -def islink(path): - """Test for symbolic link. - On WindowsNT/95 and OS/2 always returns false - """ - return False - -# alias exists to lexists -lexists = exists - -# Is a path a mount point? Either a root (with or without drive letter) -# or an UNC path with at most a / or \ after the mount point. - -def ismount(path): - """Test whether a path is a mount point (defined as root of drive)""" - unc, rest = splitunc(path) - if unc: - return rest in ("", "/", "\\") - p = splitdrive(path)[1] - return len(p) == 1 and p[0] in '/\\' - - -# Directory tree walk. -# For each directory under top (including top itself, but excluding -# '.' and '..'), func(arg, dirname, filenames) is called, where -# dirname is the name of the directory and filenames is the list -# of files (and subdirectories etc.) in the directory. -# The func may modify the filenames list, to implement a filter, -# or to impose a different order of visiting. - -def walk(top, func, arg): - """Directory tree walk with callback function. - - For each directory in the directory tree rooted at top (including top - itself, but excluding '.' and '..'), call func(arg, dirname, fnames). - dirname is the name of the directory, and fnames a list of the names of - the files and subdirectories in dirname (excluding '.' and '..'). func - may modify the fnames list in-place (e.g. via del or slice assignment), - and walk will only recurse into the subdirectories whose names remain in - fnames; this can be used to implement a filter, or to impose a specific - order of visiting. No semantics are defined for, or required of, arg, - beyond that arg is always passed to func. It can be used, e.g., to pass - a filename pattern, or a mutable object designed to accumulate - statistics. Passing None for arg is common.""" - warnings.warnpy3k("In 3.x, os.path.walk is removed in favor of os.walk.", - stacklevel=2) - try: - names = os.listdir(top) - except os.error: - return - func(arg, top, names) - for name in names: - name = join(top, name) - if isdir(name): - walk(name, func, arg) - - -# Expand paths beginning with '~' or '~user'. -# '~' means $HOME; '~user' means that user's home directory. -# If the path doesn't begin with '~', or if the user or $HOME is unknown, -# the path is returned unchanged (leaving error reporting to whatever -# function is called with the expanded path as argument). -# See also module 'glob' for expansion of *, ? and [...] in pathnames. -# (A function should also be defined to do full *sh-style environment -# variable expansion.) - -def expanduser(path): - """Expand ~ and ~user constructs. - - If user or $HOME is unknown, do nothing.""" - if path[:1] != '~': - return path - i, n = 1, len(path) - while i < n and path[i] not in '/\\': - i = i + 1 - - if 'HOME' in os.environ: - userhome = os.environ['HOME'] - elif 'USERPROFILE' in os.environ: - userhome = os.environ['USERPROFILE'] - elif not 'HOMEPATH' in os.environ: - return path - else: - try: - drive = os.environ['HOMEDRIVE'] - except KeyError: - drive = '' - userhome = join(drive, os.environ['HOMEPATH']) - - if i != 1: #~user - userhome = join(dirname(userhome), path[1:i]) - - return userhome + path[i:] - - -# Expand paths containing shell variable substitutions. -# The following rules apply: -# - no expansion within single quotes -# - '$$' is translated into '$' -# - '%%' is translated into '%' if '%%' are not seen in %var1%%var2% -# - ${varname} is accepted. -# - $varname is accepted. -# - %varname% is accepted. -# - varnames can be made out of letters, digits and the characters '_-' -# (though is not verifed in the ${varname} and %varname% cases) -# XXX With COMMAND.COM you can use any characters in a variable name, -# XXX except '^|<>='. - -def expandvars(path): - """Expand shell variables of the forms $var, ${var} and %var%. - - Unknown variables are left unchanged.""" - if '$' not in path and '%' not in path: - return path - import string - varchars = string.ascii_letters + string.digits + '_-' - res = '' - index = 0 - pathlen = len(path) - while index < pathlen: - c = path[index] - if c == '\'': # no expansion within single quotes - path = path[index + 1:] - pathlen = len(path) - try: - index = path.index('\'') - res = res + '\'' + path[:index + 1] - except ValueError: - res = res + path - index = pathlen - 1 - elif c == '%': # variable or '%' - if path[index + 1:index + 2] == '%': - res = res + c - index = index + 1 - else: - path = path[index+1:] - pathlen = len(path) - try: - index = path.index('%') - except ValueError: - res = res + '%' + path - index = pathlen - 1 - else: - var = path[:index] - if var in os.environ: - res = res + os.environ[var] - else: - res = res + '%' + var + '%' - elif c == '$': # variable or '$$' - if path[index + 1:index + 2] == '$': - res = res + c - index = index + 1 - elif path[index + 1:index + 2] == '{': - path = path[index+2:] - pathlen = len(path) - try: - index = path.index('}') - var = path[:index] - if var in os.environ: - res = res + os.environ[var] - else: - res = res + '${' + var + '}' - except ValueError: - res = res + '${' + path - index = pathlen - 1 - else: - var = '' - index = index + 1 - c = path[index:index + 1] - while c != '' and c in varchars: - var = var + c - index = index + 1 - c = path[index:index + 1] - if var in os.environ: - res = res + os.environ[var] - else: - res = res + '$' + var - if c != '': - index = index - 1 - else: - res = res + c - index = index + 1 - return res - - -# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B. -# Previously, this function also truncated pathnames to 8+3 format, -# but as this module is called "ntpath", that's obviously wrong! - -def normpath(path): - """Normalize path, eliminating double slashes, etc.""" - # Preserve unicode (if path is unicode) - backslash, dot = (u'\\', u'.') if isinstance(path, unicode) else ('\\', '.') - if path.startswith(('\\\\.\\', '\\\\?\\')): - # in the case of paths with these prefixes: - # \\.\ -> device names - # \\?\ -> literal paths - # do not do any normalization, but return the path unchanged - return path - path = path.replace("/", "\\") - prefix, path = splitdrive(path) - # We need to be careful here. If the prefix is empty, and the path starts - # with a backslash, it could either be an absolute path on the current - # drive (\dir1\dir2\file) or a UNC filename (\\server\mount\dir1\file). It - # is therefore imperative NOT to collapse multiple backslashes blindly in - # that case. - # The code below preserves multiple backslashes when there is no drive - # letter. This means that the invalid filename \\\a\b is preserved - # unchanged, where a\\\b is normalised to a\b. It's not clear that there - # is any better behaviour for such edge cases. - if prefix == '': - # No drive letter - preserve initial backslashes - while path[:1] == "\\": - prefix = prefix + backslash - path = path[1:] - else: - # We have a drive letter - collapse initial backslashes - if path.startswith("\\"): - prefix = prefix + backslash - path = path.lstrip("\\") - comps = path.split("\\") - i = 0 - while i < len(comps): - if comps[i] in ('.', ''): - del comps[i] - elif comps[i] == '..': - if i > 0 and comps[i-1] != '..': - del comps[i-1:i+1] - i -= 1 - elif i == 0 and prefix.endswith("\\"): - del comps[i] - else: - i += 1 - else: - i += 1 - # If the path is now empty, substitute '.' - if not prefix and not comps: - comps.append(dot) - return prefix + backslash.join(comps) - - -# Return an absolute path. -try: - from nt import _getfullpathname - -except ImportError: # no built-in nt module - maybe it's Jython ;) - - if os._name == 'nt' : - # on Windows so Java version of sys deals in NT paths - def abspath(path): - """Return the absolute version of a path.""" - try: - if isinstance(path, unicode): - # Result must be unicode - if path: - path = sys.getPath(path) - else: - # Empty path must return current working directory - path = os.getcwdu() - else: - # Result must be bytes - if path: - path = sys.getPath(path).encode('latin-1') - else: - # Empty path must return current working directory - path = os.getcwd() - except EnvironmentError: - pass # Bad path - return unchanged. - return normpath(path) - - else: - # not running on Windows - mock up something sensible - def abspath(path): - """Return the absolute version of a path.""" - try: - if isinstance(path, unicode): - # Result must be unicode - if path: - path = join(os.getcwdu(), path) - else: - # Empty path must return current working directory - path = os.getcwdu() - else: - # Result must be bytes - if path: - path = join(os.getcwd(), path) - else: - # Empty path must return current working directory - path = os.getcwd() - except EnvironmentError: - pass # Bad path - return unchanged. - return normpath(path) - -else: # use native Windows method on Windows - def abspath(path): - """Return the absolute version of a path.""" - - if path: # Empty path must return current working directory. - try: - path = _getfullpathname(path) - except WindowsError: - pass # Bad path - return unchanged. - elif isinstance(path, unicode): - path = os.getcwdu() - else: - path = os.getcwd() - return normpath(path) - -# realpath is a no-op on systems without islink support -realpath = abspath -# Win9x family and earlier have no Unicode filename support. -supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and - sys.getwindowsversion()[3] >= 2) - -def _abspath_split(path): - abs = abspath(normpath(path)) - prefix, rest = splitunc(abs) - is_unc = bool(prefix) - if not is_unc: - prefix, rest = splitdrive(abs) - return is_unc, prefix, [x for x in rest.split(sep) if x] - -def relpath(path, start=curdir): - """Return a relative version of a path""" - - if not path: - raise ValueError("no path specified") - - start_is_unc, start_prefix, start_list = _abspath_split(start) - path_is_unc, path_prefix, path_list = _abspath_split(path) - - if path_is_unc ^ start_is_unc: - raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" - % (path, start)) - if path_prefix.lower() != start_prefix.lower(): - if path_is_unc: - raise ValueError("path is on UNC root %s, start on UNC root %s" - % (path_prefix, start_prefix)) - else: - raise ValueError("path is on drive %s, start on drive %s" - % (path_prefix, start_prefix)) - # Work out how much of the filepath is shared by start and path. - i = 0 - for e1, e2 in zip(start_list, path_list): - if e1.lower() != e2.lower(): - break - i += 1 - - rel_list = [pardir] * (len(start_list)-i) + path_list[i:] - if not rel_list: - return curdir - return join(*rel_list) diff --git a/Lib/os.py b/Lib/os.py index b759744e3..8d4225cea 100644 --- a/Lib/os.py +++ b/Lib/os.py @@ -24,6 +24,7 @@ #' import sys, errno +from org.python.core import PyShadowString _names = sys.builtin_module_names @@ -38,7 +39,6 @@ def _get_exports_list(module): except AttributeError: return [n for n in dir(module) if n[0] != '_'] -name = 'java' if 'posix' in _names: _name = 'posix' linesep = '\n' @@ -131,6 +131,8 @@ def _get_exports_list(module): else: raise ImportError, 'no os specific module found' +name = PyShadowString('java', _name) + sys.modules['os.path'] = path from os.path import (curdir, pardir, sep, pathsep, defpath, extsep, altsep, devnull) diff --git a/Lib/platform.py b/Lib/platform.py index 2da6383a4..70901ab9b 100755 --- a/Lib/platform.py +++ b/Lib/platform.py @@ -588,6 +588,12 @@ def win32_ver(release='',version='',csd='',ptype=''): from win32con import HKEY_LOCAL_MACHINE, VER_PLATFORM_WIN32_NT, \ VER_PLATFORM_WIN32_WINDOWS, VER_NT_WORKSTATION except ImportError: + if sys.platform.startswith("java"): + if os._name == 'nt': + unm = os.uname() + return unm[2], unm[3], csd, ptype + else: + return release, version, csd, ptype # Emulate the win32api module using Python APIs try: sys.getwindowsversion diff --git a/Lib/pycimport.py b/Lib/pycimport.py index bcccaa58d..bf7f308a2 100644 --- a/Lib/pycimport.py +++ b/Lib/pycimport.py @@ -5,6 +5,9 @@ __debugging__ = False +# Todo: This should be stored in a central place. +supported_magic = 62211 # CPython 2.7 + def __readPycHeader(file): def read(): return ord(file.read(1)) @@ -26,6 +29,7 @@ class __Importer(object): def __init__(self, path): if __debugging__: print "Importer invoked" self.__path = path + def find_module(self, fullname, path=None): if __debugging__: print "Importer.find_module(fullname=%s, path=%s)" % ( @@ -42,6 +46,9 @@ def find_module(self, fullname, path=None): except: return None # abort! not a valid pyc-file f.close() + # Todo: This check should also be in Unmarshaller + if magic != supported_magic: + return None # bytecode version mismatch if os.path.exists(pyfile): pytime = os.stat(pyfile).st_mtime if pytime > mtime: @@ -49,12 +56,16 @@ def find_module(self, fullname, path=None): return self else: return None # abort! pyc-file does not exist + def load_module(self, fullname): path = fullname.split('.') path[-1] += '.pyc' filename = os.path.join(self.__path, *path) f = open(filename, 'rb') magic, mtime = __readPycHeader(f) + if magic != supported_magic: + if __debugging__: print "Unsupported bytecode version:", fullname + return None #code = Unmarshaller(f, magic=magic).load() code = Unmarshaller(f).load() if __debugging__: print "Successfully loaded:", fullname @@ -63,6 +74,7 @@ def load_module(self, fullname): class __MetaImporter(object): def __init__(self): self.__importers = {} + def find_module(self, fullname, path): if __debugging__: print "MetaImporter.find_module(%s, %s)" % ( repr(fullname), repr(path)) diff --git a/Lib/ssl.py b/Lib/ssl.py index 965c35dcc..972d9305a 100644 --- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -6,7 +6,6 @@ from java.io import BufferedInputStream from java.security import KeyStore, KeyStoreException from java.security.cert import CertificateParsingException -from javax.net.ssl import TrustManagerFactory from javax.naming.ldap import LdapName from java.lang import IllegalArgumentException, System import logging @@ -19,11 +18,16 @@ try: # jarjar-ed version from org.python.netty.channel import ChannelInitializer - from org.python.netty.handler.ssl import SslHandler + from org.python.netty.handler.ssl import SslHandler, SslProvider, SslContextBuilder, ClientAuth + from org.python.netty.handler.ssl.util import SimpleTrustManagerFactory, InsecureTrustManagerFactory + from org.python.netty.buffer import ByteBufAllocator + except ImportError: # dev version from extlibs from io.netty.channel import ChannelInitializer - from io.netty.handler.ssl import SslHandler + from io.netty.handler.ssl import SslHandler, SslProvider, SslContextBuilder, ClientAuth + from io.netty.handler.ssl.util import SimpleTrustManagerFactory, InsecureTrustManagerFactory + from io.netty.buffer import ByteBufAllocator from _socket import ( SSLError, raises_java_exception, @@ -45,7 +49,7 @@ error as socket_error) from _sslcerts import _get_openssl_key_manager, _extract_cert_from_data, _extract_certs_for_paths, \ - NoVerifyX509TrustManager, _str_hash_key_entry, _get_ecdh_parameter_spec, CompositeX509TrustManager + _str_hash_key_entry, _get_ecdh_parameter_spec, CompositeX509TrustManagerFactory from _sslcerts import SSLContext as _JavaSSLContext from java.text import SimpleDateFormat @@ -56,6 +60,13 @@ from javax.security.auth.x500 import X500Principal from org.ietf.jgss import Oid +try: + # requires Java 8 or higher for this support + from javax.net.ssl import SNIHostName, SNIMatcher + HAS_SNI = True +except ImportError: + HAS_SNI = False + log = logging.getLogger("_socket") @@ -67,6 +78,10 @@ CERT_NONE, CERT_OPTIONAL, CERT_REQUIRED = range(3) +_CERT_TO_CLIENT_AUTH = {CERT_NONE: ClientAuth.NONE, + CERT_OPTIONAL: ClientAuth.OPTIONAL, + CERT_REQUIRED: ClientAuth.REQUIRE} + # Do not support PROTOCOL_SSLv2, it is highly insecure and it is optional _, PROTOCOL_SSLv3, PROTOCOL_SSLv23, PROTOCOL_TLSv1, PROTOCOL_TLSv1_1, PROTOCOL_TLSv1_2 = range(6) _PROTOCOL_NAMES = { @@ -77,15 +92,23 @@ PROTOCOL_TLSv1_2: 'TLSv1.2' } -OP_ALL, OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_TLSv1 = range(4) +OP_ALL = 0 +OP_NO_SSLv2 = 1 +OP_NO_SSLv3 = 2 +OP_NO_TLSv1 = 4 +OP_NO_TLSv1_1 = 8 +OP_NO_TLSv1_2 = 16 OP_SINGLE_DH_USE, OP_NO_COMPRESSION, OP_CIPHER_SERVER_PREFERENCE, OP_SINGLE_ECDH_USE = 1048576, 131072, 4194304, 524288 VERIFY_DEFAULT, VERIFY_CRL_CHECK_LEAF, VERIFY_CRL_CHECK_CHAIN, VERIFY_X509_STRICT = 0, 4, 12, 32 +HAS_TLSv1_3 = False + CHANNEL_BINDING_TYPES = [] # https://docs.python.org/2/library/ssl.html#ssl.HAS_ALPN etc... -HAS_ALPN, HAS_NPN, HAS_ECDH, HAS_SNI = False, False, True, False +HAS_ALPN, HAS_NPN, HAS_ECDH = False, False, True + # TODO not supported on jython yet # Disable weak or insecure ciphers by default @@ -290,7 +313,6 @@ def get_default_verify_paths(): if java_cert_file is not None and os.path.isfile(java_cert_file): cafile = java_cert_file - capath = os.path.dirname(java_cert_file) else: if default_cert_dir_env is not None: capath = default_cert_dir_env if os.path.isdir(default_cert_dir_env) else None @@ -307,7 +329,7 @@ def get_default_verify_paths(): capath = os.path.dirname(cafile) return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None, - capath if os.path.isdir(capath) else None, + capath if capath and os.path.isdir(capath) else None, 'SSL_CERT_FILE', default_cert_file_env, 'SSL_CERT_DIR', default_cert_dir_env) @@ -578,12 +600,17 @@ def wrap_child(child): def context(self): return self._context + @context.setter + def context(self, context): + self._context = context + def setup_engine(self, addr): if self.engine is None: # http://stackoverflow.com/questions/13390964/java-ssl-fatal-error-80-unwrapping-net-record-after-adding-the-https-en self.engine = self._context._createSSLEngine( addr, self.server_hostname, - cert_file=getattr(self, "certfile", None), key_file=getattr(self, "keyfile", None)) + cert_file=getattr(self, "certfile", None), key_file=getattr(self, "keyfile", None), + server_side=self.server_side) self.engine.setUseClientMode(not self.server_side) def connect(self, addr): @@ -666,12 +693,12 @@ def handshake_step(result): pass # see # http://stackoverflow.com/questions/24628271/exception-in-netty-io-netty-util-concurrent-blockingoperationexception - # - handshake in the child thread pool - else: - self._sock._handle_channel_future(self._handshake_future, "SSL handshake") + # - we are doing this in the handler thread! + return + self._sock._handle_channel_future(handshake, "SSL handshake", wait=True) def dup(self): - raise NotImplemented("Can't dup() %s instances" % + raise NotImplementedError("Can't dup() %s instances" % self.__class__.__name__) @raises_java_exception @@ -1013,12 +1040,11 @@ def RAND_egd(path): def RAND_add(bytes, entropy): pass - class SSLContext(object): _jsse_keyType_names = ('RSA', 'DSA', 'DH_RSA', 'DH_DSA', 'EC', 'EC_EC', 'EC_RSA') - def __init__(self, protocol): + def __init__(self, protocol, options=None): try: self._protocol_name = _PROTOCOL_NAMES[protocol] except KeyError: @@ -1031,7 +1057,33 @@ def __init__(self, protocol): self._check_hostname = False # defaults from _ssl.c - self.options = OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 + if options: + self.options = options + else: + # secure defaults + self.options = OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 | OP_NO_TLSv1 | OP_NO_TLSv1_1 + + protocols = _PROTOCOL_NAMES.values() + # psd: assuming darjus is right I should do the same change here + protocols.remove(_PROTOCOL_NAMES[PROTOCOL_SSLv23]) # darjus: at least my Java does not let me use v2 + protocols.append('SSL') + if self.options == OP_ALL: + ## just use the whole list of _PROTOCOL_NAMES possibly in the future grab the JVM defaults + pass + else: + if OP_NO_SSLv2 & self.options: + protocols.remove('SSL') # darjus: at least my Java does not let me use v2 + if OP_NO_SSLv3 & self.options: + protocols.remove(_PROTOCOL_NAMES[PROTOCOL_SSLv3]) + if OP_NO_TLSv1 & self.options: + protocols.remove(_PROTOCOL_NAMES[PROTOCOL_TLSv1]) + if OP_NO_TLSv1_1 & self.options: + protocols.remove(_PROTOCOL_NAMES[PROTOCOL_TLSv1_1]) + if OP_NO_TLSv1_2 & self.options: + protocols.remove(_PROTOCOL_NAMES[PROTOCOL_TLSv1_2]) + + self.allowed_protocols = protocols + self._verify_flags = VERIFY_DEFAULT self._verify_mode = CERT_NONE self._ciphers = None @@ -1044,6 +1096,8 @@ def __init__(self, protocol): self._key_managers = None + self._server_name_callback = None + def wrap_socket(self, sock, server_side=False, do_handshake_on_connect=True, suppress_ragged_eofs=True, @@ -1054,36 +1108,50 @@ def wrap_socket(self, sock, server_side=False, server_hostname=server_hostname, _context=self) - def _createSSLEngine(self, addr, hostname=None, cert_file=None, key_file=None): - trust_managers = [NoVerifyX509TrustManager()] - if self.verify_mode == CERT_REQUIRED: - tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - tmf.init(self._trust_store) - trust_managers = [CompositeX509TrustManager(tmf.getTrustManagers())] + def _createSSLEngine(self, addr, hostname=None, cert_file=None, key_file=None, server_side=False): + tmf = InsecureTrustManagerFactory.INSTANCE + if self.verify_mode != CERT_NONE: + # XXX need to refactor so we don't have to get trust managers twice + stmf = SimpleTrustManagerFactory.getInstance(SimpleTrustManagerFactory.getDefaultAlgorithm()) + stmf.init(self._trust_store) - context = _JavaSSLContext.getInstance(self._protocol_name) + tmf = CompositeX509TrustManagerFactory(stmf.getTrustManagers()) + tmf.init(self._trust_store) + kmf = self._key_managers if self._key_managers is None: - context.init( - _get_openssl_key_manager( - cert_file=cert_file, key_file=key_file).getKeyManagers(), - trust_managers, None) - else: - context.init( - self._key_managers.getKeyManagers(), - trust_managers, None) + kmf = _get_openssl_key_manager(cert_file=cert_file, key_file=key_file) - # addr could be ipv6, only extract relevant parts - engine = context.createSSLEngine((hostname or addr[0]), addr[1]) + context_builder = None - # apparently this can be used to enforce hostname verification - if hostname is not None and self._check_hostname: - params = engine.getSSLParameters() - params.setEndpointIdentificationAlgorithm('HTTPS') - engine.setSSLParameters(params) + if not server_side: + context_builder = SslContextBuilder.forClient() + + if kmf: + if server_side: + context_builder = SslContextBuilder.forServer(kmf) + else: + context_builder = context_builder.keyManager(kmf) + + context_builder = context_builder.trustManager(tmf) + context_builder = context_builder.sslProvider(SslProvider.JDK) + context_builder = context_builder.clientAuth(_CERT_TO_CLIENT_AUTH[self.verify_mode]) if self._ciphers is not None: - engine.setEnabledCipherSuites(self._ciphers) + context_builder = context_builder.ciphers(self._ciphers) + + if self._check_hostname: + engine = context_builder.build().newEngine(ByteBufAllocator.DEFAULT, hostname, addr[1]) + else: + engine = context_builder.build().newEngine(ByteBufAllocator.DEFAULT, addr[0], addr[1]) + + params = engine.getSSLParameters() + params.setProtocols(self.allowed_protocols) + if self._check_hostname and HAS_SNI: + params.setEndpointIdentificationAlgorithm('HTTPS') + params.setServerNames([SNIHostName(hostname)]) + + engine.setSSLParameters(params) return engine @@ -1120,9 +1188,13 @@ def load_verify_locations(self, cafile=None, capath=None, cadata=None): if os.path.isfile(possible_cafile): cafiles.append(possible_cafile) elif os.path.isfile(possible_cafile): - with open(possible_cafile) as f: - if PEM_HEADER in f.read(): - cafiles.append(possible_cafile) + try: + with open(possible_cafile) as f: + if PEM_HEADER in f.read(): + cafiles.append(possible_cafile) + except IOError: + log.debug("Not including %s file as a possible cafile due to permissions error" % possible_cafile) + pass # Probably permissions related...ignore certs = [] private_key = None @@ -1163,7 +1235,10 @@ def set_npn_protocols(self, protocols): raise NotImplementedError() def set_servername_callback(self, server_name_callback): - raise NotImplementedError() + if not callable(server_name_callback) and server_name_callback is not None: + raise TypeError("{!r} is not callable".format(server_name_callback)) + self._server_name_callback = server_name_callback + def load_dh_params(self, dhfile): # TODO? diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 8e75fad94..3b4824aa0 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -432,12 +432,14 @@ class pywintypes: import java.io.FileNotFoundException import java.lang.IllegalArgumentException import java.lang.IllegalThreadStateException + import java.lang.Process import java.lang.ProcessBuilder import java.lang.System import java.lang.Thread import java.nio.ByteBuffer import org.python.core.io.RawIOBase import org.python.core.io.StreamIO + from org.python.core.Py import fileSystemDecode else: import select _has_poll = hasattr(select, 'poll') @@ -490,6 +492,38 @@ def _eintr_retry_call(func, *args): raise +# XXX This function is only used by multiprocessing and the test suite, +# but it's here so that it can be imported when Python is compiled without +# threads. + +def _args_from_interpreter_flags(): + """Return a list of command-line arguments reproducing the current + settings in sys.flags and sys.warnoptions.""" + flag_opt_map = { + 'debug': 'd', + # 'inspect': 'i', + # 'interactive': 'i', + 'optimize': 'O', + 'dont_write_bytecode': 'B', + 'no_user_site': 's', + 'no_site': 'S', + 'ignore_environment': 'E', + 'verbose': 'v', + 'bytes_warning': 'b', + 'py3k_warning': '3', + } + args = [] + for flag, opt in flag_opt_map.items(): + v = getattr(sys.flags, flag) + if v > 0: + args.append('-' + opt * v) + if getattr(sys.flags, 'hash_randomization') != 0: + args.append('-R') + for opt in sys.warnoptions: + args.append('-W' + opt) + return args + + def call(*popenargs, **kwargs): """Run command with arguments. Wait for command to complete, then return the returncode attribute. @@ -779,7 +813,7 @@ def _setup_env(env, builder_env): maintain those byte values (which may be butchered as Strings) for the subprocess if they haven't been modified. """ - # Determine what's safe to merge + # Determine what's necessary to merge (new or different) merge_env = dict((key, value) for key, value in env.iteritems() if key not in builder_env or builder_env.get(key) != value) @@ -789,8 +823,10 @@ def _setup_env(env, builder_env): for entry in entries: if entry.getKey() not in env: entries.remove() - - builder_env.putAll(merge_env) + # add anything new or different in env + for key, value in merge_env.iteritems(): + # If the new value is bytes, assume it to be FS-encoded + builder_env.put(key, fileSystemDecode(value)) class Popen(object): @@ -1308,9 +1344,6 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, args = _cmdline2listimpl(args) else: args = list(args) - # NOTE: CPython posix (execv) will str() any unicode - # args first, maybe we should do the same on - # posix. Windows passes unicode through, however if any(not isinstance(arg, (str, unicode)) for arg in args): raise TypeError('args must contain only strings') args = _escape_args(args) @@ -1321,6 +1354,11 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, if executable is not None: args[0] = executable + # NOTE: CPython posix (execv) will FS-encode any unicode args, but + # pass on bytes unchanged, because that's what the system expects. + # Java expects unicode, so we do the converse: leave unicode + # unchanged but FS-decode any supplied as bytes. + args = [fileSystemDecode(arg) for arg in args] builder = java.lang.ProcessBuilder(args) if stdin is None: @@ -1330,16 +1368,20 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, if stderr is None: builder.redirectError(java.lang.ProcessBuilder.Redirect.INHERIT) - # os.environ may be inherited for compatibility with CPython + # os.environ may be inherited for compatibility with CPython. + # Elements taken from os.environ are FS-decoded to unicode. _setup_env(dict(os.environ if env is None else env), builder.environment()) + # The current working directory must also be unicode. if cwd is None: - cwd = os.getcwd() - elif not os.path.exists(cwd): - raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), cwd) - elif not os.path.isdir(cwd): - raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR), cwd) + cwd = os.getcwdu() + else: + cwd = fileSystemDecode(cwd) + if not os.path.exists(cwd): + raise OSError(errno.ENOENT, os.strerror(errno.ENOENT), cwd) + elif not os.path.isdir(cwd): + raise OSError(errno.ENOTDIR, os.strerror(errno.ENOTDIR), cwd) builder.directory(java.io.File(cwd)) # Let Java manage redirection of stderr to stdout (it's more @@ -1376,7 +1418,12 @@ def _get_private_field(self, object, field_name): else: return field - if os._name not in _win_oses: + if hasattr(java.lang.Process, "pid"): # Java 9 onwards + + def _get_pid(self, pid_field=None): + return self._process.pid() + + elif os._name not in _win_oses: def _get_pid(self, pid_field='pid'): field = self._get_private_field(self._process, pid_field) @@ -1890,9 +1937,10 @@ def _os_system(command): args = _cmdline2listimpl(command) args = _escape_args(args) args = _shell_command + args - cwd = os.getcwd() - + cwd = os.getcwdu() + # Python supplies FS-encoded arguments while Java expects String + args = [fileSystemDecode(arg) for arg in args] builder = java.lang.ProcessBuilder(args) builder.directory(java.io.File(cwd)) diff --git a/Lib/sysconfig.py b/Lib/sysconfig.py index 829bce748..838c4e12b 100644 --- a/Lib/sysconfig.py +++ b/Lib/sysconfig.py @@ -5,6 +5,11 @@ import os from os.path import pardir, realpath +def fileSystemEncode(path): + if isinstance(path, unicode): + return path.encode(sys.getfilesystemencoding()) + return path + _INSTALL_SCHEMES = { 'posix_prefix': { 'stdlib': '{base}/lib/python{py_version_short}', @@ -116,6 +121,7 @@ def _safe_realpath(path): try: + path = fileSystemEncode(path) return realpath(path) except OSError: return path diff --git a/Lib/test/capath/efa5f9c3.0 b/Lib/test/capath/efa5f9c3.0 new file mode 100644 index 000000000..2b1760747 --- /dev/null +++ b/Lib/test/capath/efa5f9c3.0 @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG +A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg +Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw +HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx +FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu +aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD +DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2 +RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix +IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx +jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK +DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3 +TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI +aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU +OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH +OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg +7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ +8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB +AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW +gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP +ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN +9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9 +1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH +AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e +W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk +BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8 +XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku +B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL +Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV +J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg== +-----END CERTIFICATE----- diff --git a/Lib/test/import_nonexistent.py b/Lib/test/import_nonexistent.py index 18dd54293..1219df923 100644 --- a/Lib/test/import_nonexistent.py +++ b/Lib/test/import_nonexistent.py @@ -1,3 +1,6 @@ +# Test material for: +# SecurityManagerTest.test_nonexistent_import_with_security (test_java_integration.py) + try: import nonexistent_module except ImportError: diff --git a/Lib/test/import_star_from_java.py b/Lib/test/import_star_from_java.py index 6964e028b..702c68efd 100644 --- a/Lib/test/import_star_from_java.py +++ b/Lib/test/import_star_from_java.py @@ -1,4 +1,13 @@ -from java.util.regex import * - +# Test material for ImpTestCase.test_import_star (test_import_jy.py) +# +from java.util.regex import * # Module: java.base p = Pattern.compile("foo") assert p.flags() == 0 + +from java.sql import * # Module: java.sql +d = Date(1541492230300L) +assert str(d) == '2018-11-06' + +from java.awt import * # Module: java.desktop +assert Color(255,0,255) == Color.MAGENTA + diff --git a/Lib/test/large_methods.py b/Lib/test/large_methods.py new file mode 100644 index 000000000..34ca47082 --- /dev/null +++ b/Lib/test/large_methods.py @@ -0,0 +1,63602 @@ + +def large_function(): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + return 'large '+str(count) + +def very_large_function(): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + + return 'very large '+str(count) + +def small_function(): + count = 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + return 'small '+str(count) + +class OversizedMethodHolder(): + # test name-ambiguity + def large_function(self): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + return 'large_method '+str(count) + diff --git a/Lib/test/large_methods.pyc b/Lib/test/large_methods.pyc new file mode 100644 index 000000000..b37b8d13f Binary files /dev/null and b/Lib/test/large_methods.pyc differ diff --git a/Lib/test/large_module.py b/Lib/test/large_module.py new file mode 100644 index 000000000..e9dd1d2a5 --- /dev/null +++ b/Lib/test/large_module.py @@ -0,0 +1,65938 @@ + +def large_function(): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + return 'large '+str(count) + +def very_large_function(): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + + return 'very large '+str(count) + +def small_function(): + count = 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + return 'small '+str(count) + +class OversizedMethodHolder(): + # test name-ambiguity + def large_function(self): + count = 0 + # 0 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1300 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1400 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1500 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1600 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1700 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1800 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 1900 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2000 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2100 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2200 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +10 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +20 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +30 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +40 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +50 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +60 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +70 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +80 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 # +90 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 + count += 1 #+100 + # 2300 + return 'large_method '+str(count) + +count = 0 +# 0 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 100 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 200 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 300 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 400 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 500 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 600 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 700 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 800 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 900 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1000 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1100 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1200 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1300 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1400 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1500 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1600 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1700 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1800 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 1900 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 2000 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 2100 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 2200 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +20 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +30 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +40 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +50 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +60 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +70 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +80 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +90 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 #+100 +# 2300 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 +count += 1 # +10 + diff --git a/Lib/test/large_module.pyc b/Lib/test/large_module.pyc new file mode 100644 index 000000000..a3c2ca8e2 Binary files /dev/null and b/Lib/test/large_module.pyc differ diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py index feca87765..7353e9813 100644 --- a/Lib/test/lock_tests.py +++ b/Lib/test/lock_tests.py @@ -409,8 +409,14 @@ def f(): results.append(t2 - t1) Bunch(f, N).wait_for_finished() self.assertEqual(len(results), 5) + # Fudge factor for running on the JVM - actual waits on + # some OS platforms might be like this example, + # 0.199999809265, slightly less than 0.2 seconds. To avoid + # unnecessary flakiness in testing, make epsilon + # relatively large: + epsilon = 0.01 for dt in results: - self.assertTrue(dt >= 0.2, dt) + self.assertTrue(dt >= 0.2 - epsilon, dt) class BaseSemaphoreTests(BaseTestCase): diff --git a/Lib/test/pbcvm/test/test_builtin_pyc.pyc b/Lib/test/pbcvm/test/test_builtin_pyc.pyc index df2d3e1b9..14847335f 100644 Binary files a/Lib/test/pbcvm/test/test_builtin_pyc.pyc and b/Lib/test/pbcvm/test/test_builtin_pyc.pyc differ diff --git a/Lib/test/pbcvm/test/test_exceptions_pyc.pyc b/Lib/test/pbcvm/test/test_exceptions_pyc.pyc index 4a71ad373..650492abd 100644 Binary files a/Lib/test/pbcvm/test/test_exceptions_pyc.pyc and b/Lib/test/pbcvm/test/test_exceptions_pyc.pyc differ diff --git a/Lib/test/pbcvm/test/test_types_pyc.pyc b/Lib/test/pbcvm/test/test_types_pyc.pyc index 82b540c46..2279f3183 100644 Binary files a/Lib/test/pbcvm/test/test_types_pyc.pyc and b/Lib/test/pbcvm/test/test_types_pyc.pyc differ diff --git a/Lib/test/print_sans_lib.py b/Lib/test/print_sans_lib.py index 96e6646ea..5cdcac536 100644 --- a/Lib/test/print_sans_lib.py +++ b/Lib/test/print_sans_lib.py @@ -1,4 +1,9 @@ +# Used by test_codec_jy::CodecsTestCase.test_print_sans_lib. +# Run without importing site module so codec registry is not initialised yet. import sys -sys.path = [path for path in sys.path if not path.startswith('/')] +from os.path import basename +# Hide standard library from import mechanism so the Python codec cannot be found. +sys.path = [p for p in sys.path if basename(p).lower() != 'lib'] +# Can we still encode and decode utf-8? encoded = u'hi'.encode("utf-8") encoded.decode('utf-8') diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index bcb222e04..c19449d0f 100644 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -378,7 +378,6 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, test_times = [] test_support.verbose = verbose # Tell tests to be moderately quiet test_support.use_resources = use_resources - test_support.junit_xml_dir = junit_xml save_modules = sys.modules.keys() skips = _ExpectedSkips() @@ -398,6 +397,22 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, failures.keep_only(tests) skips.keep_only(tests) + # Output some platform information. Loosely based on CPython 3.6 regrtest. + if (verbose or len(tests)>1) and not (quiet or single): + # Print basic platform information + for t in sys.version.splitlines(): + print "==", t + print "== platform:", sys.platform + print "== encodings: stdin=%s, stdout=%s, FS=%s" % ( + sys.stdin.encoding, sys.stdout.encoding, + sys.getfilesystemencoding()) + try: + import locale + print "== locale: default=%s, actual=%s" % ( + locale.getdefaultlocale(), locale.getlocale()) + except ImportError: + pass + for test in tests: if not quiet: print test @@ -584,6 +599,7 @@ def runtest_inner(test, verbose, quiet, test_times, save_stderr = sys.stderr sys.stdout = stdout = Tee(sys.stdout) sys.stderr = stderr = Tee(sys.stderr) + test_support.junit_xml_dir = junit_xml_dir try: if capture_stdout: sys.stdout = capture_stdout @@ -614,6 +630,7 @@ def runtest_inner(test, verbose, quiet, test_times, test_times.append((test_time, test)) finally: sys.stdout = save_stdout + test_support.junit_xml_dir = None if junit_xml_dir: sys.stderr = save_stderr test_time = time.time() - start_time @@ -1306,6 +1323,7 @@ def skip_conditional_support(test_module,module_name): test_peepholer test_pyclbr test_pyexpat + test_ssl # overridden by test_ssl_jy test_stringprep # UnicodeDecodeError test_threadsignals test_transformer @@ -1328,7 +1346,6 @@ def skip_conditional_support(test_module,module_name): test_locale test_profile test_pydoc # Hangs with prompt (Windows) - test_select # Unconnected client socket should be selectable test_sundry # ImportError: No module named audiodev test_sys_setprofile # revisit for GC @@ -1337,8 +1354,8 @@ def skip_conditional_support(test_module,module_name): # Unreliable tests test_asynchat # test_gc # Rare failures depending on timing of Java gc - # test_logging - test_tarfile # flakey (Windows) + test_logging # Hangs, though ok run singly. Issue #2536 + test_tarfile # flakey everywhere. Issue #2574 # test_urllib2net # unexpected output makes this a failure to regrtest.py # Failing tests here are because of lack of STARTTLS; see http://bugs.jython.org/issue2447 @@ -1354,16 +1371,19 @@ def skip_conditional_support(test_module,module_name): 'java.nt': # Expected to fail on Windows """ - test_mailbox # fails miserably and ruins other tests - test_os_jy # Locale tests run and fail on Cygwin - test_popen # http://bugs.python.org/issue1559298 - test_runpy # OSError: unlink() - test_urllib2 # file not on local host (likely Windows only) + test_calendar # Same, covered by test_calendar_jy + test_email # test_email_jy overrides for correct locale handling + test_mailbox # fails miserably and ruins other tests + # test_popen # Passes, but see http://bugs.python.org/issue1559298 + test_select_new # Hangs (Windows), though ok run singly + test_strptime # Fails on JDK 9+ due to locale strings change + # Covered by test_strptime_jy until the beta locale + # behaviour becomes the default + test_urllib2 # file not on local host (likely Windows only) """, 'java.posix': # Expected to fail on Linux """ - test_codecencodings_tw # Fails in test_multibytecodec_support.py test_jython_launcher # /usr/bin/env: python2.7 -E: No such file or directory # These leak file handles on a grand scale (observed on Ubuntu 14.04), diff --git a/Lib/test/script_helper.py b/Lib/test/script_helper.py index 32a76493c..0f7f5c3fb 100644 --- a/Lib/test/script_helper.py +++ b/Lib/test/script_helper.py @@ -20,6 +20,8 @@ from test.test_support import strip_python_stderr +_IS_JYTHON_WINDOWS = sys.platform.startswith('java') and os._name == 'nt' + # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): cmd_line = [sys.executable] @@ -101,7 +103,9 @@ def temp_dir(): try: yield dirname finally: - shutil.rmtree(dirname) + # On Windows, unlink failures within rmtree often mask the true nature + # of a failing test (or sometimes a passing one). + shutil.rmtree(dirname, ignore_errors=_IS_JYTHON_WINDOWS) def make_script(script_dir, script_basename, source): script_filename = script_basename+os.extsep+'py' diff --git a/Lib/test/selfsigned_pythontestdotnet.pem b/Lib/test/selfsigned_pythontestdotnet.pem index b6d259bcb..2b1760747 100644 --- a/Lib/test/selfsigned_pythontestdotnet.pem +++ b/Lib/test/selfsigned_pythontestdotnet.pem @@ -1,16 +1,34 @@ -----BEGIN CERTIFICATE----- -MIIClTCCAf6gAwIBAgIJAKGU95wKR8pTMA0GCSqGSIb3DQEBBQUAMHAxCzAJBgNV -BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u -IFNvZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMMGnNlbGYtc2lnbmVkLnB5dGhv -bnRlc3QubmV0MB4XDTE0MTEwMjE4MDkyOVoXDTI0MTAzMDE4MDkyOVowcDELMAkG -A1UEBhMCWFkxFzAVBgNVBAcMDkNhc3RsZSBBbnRocmF4MSMwIQYDVQQKDBpQeXRo -b24gU29mdHdhcmUgRm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0 -aG9udGVzdC5uZXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANDXQXW9tjyZ -Xt0Iv2tLL1+jinr4wGg36ioLDLFkMf+2Y1GL0v0BnKYG4N1OKlAU15LXGeGer8vm -Sv/yIvmdrELvhAbbo3w4a9TMYQA4XkIVLdvu3mvNOAet+8PMJxn26dbDhG809ALv -EHY57lQsBS3G59RZyBPVqAqmImWNJnVzAgMBAAGjNzA1MCUGA1UdEQQeMByCGnNl -bGYtc2lnbmVkLnB5dGhvbnRlc3QubmV0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN -AQEFBQADgYEAIuzAhgMouJpNdf3URCHIineyoSt6WK/9+eyUcjlKOrDoXNZaD72h -TXMeKYoWvJyVcSLKL8ckPtDobgP2OTt0UkyAaj0n+ZHaqq1lH2yVfGUA1ILJv515 -C8BqbvVZuqm3i7ygmw3bqE/lYMgOrYtXXnqOrz6nvsE6Yc9V9rFflOM= +MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG +A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg +Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw +HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx +FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu +aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD +DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2 +RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix +IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx +jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK +DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3 +TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI +aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU +OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH +OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg +7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ +8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB +AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW +gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP +ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN +9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9 +1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH +AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e +W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk +BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8 +XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku +B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL +Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV +J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg== -----END CERTIFICATE----- diff --git a/Lib/test/shortname.bat b/Lib/test/shortname.bat new file mode 100644 index 000000000..df614bccb --- /dev/null +++ b/Lib/test/shortname.bat @@ -0,0 +1,4 @@ +@ECHO OFF +REM Supports windows-specific shortname tests in test_chdir.py +echo %~s1 + diff --git a/Lib/test/syspath_initializer.jar b/Lib/test/syspath_initializer.jar new file mode 100644 index 000000000..374041003 Binary files /dev/null and b/Lib/test/syspath_initializer.jar differ diff --git a/Lib/test/test_StringIO_jy.py b/Lib/test/test_StringIO_jy.py index f2cad2cc4..b3f0d9676 100644 --- a/Lib/test/test_StringIO_jy.py +++ b/Lib/test/test_StringIO_jy.py @@ -12,6 +12,12 @@ def test_differences_handling_unicode(self): self.assertEqual(u'foo', cStringIO.StringIO(u'foo').read()) self.assertEqual('foo', cStringIO.StringIO(u'foo').read()) + def test_unicode_encode_error(self): + # See issue #2527 + uc = u'\u4e2d\u6587' + self.assertRaises(UnicodeEncodeError, lambda: cStringIO.StringIO(uc)) + + class TestWrite(unittest.TestCase): def test_write_seek_write(self): f = cStringIO.StringIO() diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index fbdd8d0a4..e30b0861e 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -63,6 +63,7 @@ def test_len(self): a = array.array(self.typecode, self.example) self.assertEqual(len(a), len(self.example)) + @unittest.skipIf(test_support.is_jython, "Specific to CPython (memory address)") def test_buffer_info(self): a = array.array(self.typecode, self.example) self.assertRaises(TypeError, a.buffer_info, 42) @@ -75,9 +76,7 @@ def test_buffer_info(self): def test_byteswap(self): if test_support.is_jython and self.typecode == 'u': - # Jython unicodes are already decoded from utf16, - # so this doesn't make sense - return + self.skipTest("Jython unicode byteswap not implemented") a = array.array(self.typecode, self.example) self.assertRaises(TypeError, a.byteswap, 42) if a.itemsize in (1, 2, 4, 8): @@ -280,25 +279,6 @@ def checkSlice(x, y, z=None): checkSlice(None, D-R-1, -1) checkSlice(R-1, None, -1) - def test_filewrite(self): - a = array.array(self.typecode, 2*self.example) - f = open(test_support.TESTFN, 'wb') - try: - f.write(a) - f.close() - b = array.array(self.typecode) - f = open(test_support.TESTFN, 'rb') - b.fromfile(f, len(self.example)) - self.assertEqual(b, array.array(self.typecode, self.example)) - self.assertNotEqual(a, b) - b.fromfile(f, len(self.example)) - self.assertEqual(a, b) - f.close() - finally: - if not f.closed: - f.close() - test_support.unlink(test_support.TESTFN) - def test_repr(self): a = array.array(self.typecode, 2*self.example) self.assertEqual(a, eval(repr(a), {"array": array.array})) @@ -836,6 +816,11 @@ def test_buffer(self): b = buffer(a) self.assertEqual(b[0], a.tostring()[0]) + def test_not_memoryview(self): + # In Jython we are careful *not* to support memoryview + a = array.array(self.typecode, self.example) + self.assertRaises(TypeError, memoryview, a) + def test_weakref(self): s = array.array(self.typecode, self.example) p = proxy(s) @@ -859,66 +844,6 @@ def test_subclass_with_kwargs(self): # SF bug #1486663 -- this used to erroneously raise a TypeError ArraySubclassWithKwargs('b', newarg=1) - @unittest.skipUnless(test_support.is_jython, "array supports buffer interface in Jython") - def test_resize_forbidden(self): - # Test that array resizing is forbidden with buffer exports (Jython addition). - # Test adapted from corresponding one in test_bytes. - # We can't resize an array when there are buffer exports, even - # if it wouldn't reallocate the underlying array. - # Furthermore, no destructive changes to the buffer may be applied - # before raising the error. - a = array.array(self.typecode, self.example) - def resize(n): - "n = -1 -> Smaller, 0 -> the same, or 1 -> larger." - a[1:-1] = array.array(self.typecode, self.example[1-n:-1]) - - v = memoryview(a) - orig = a[:] - - self.assertRaises(BufferError, resize, -1) - self.assertEqual(a, orig) - #self.assertRaises(BufferError, resize, 0) - #self.assertEqual(a, orig) - self.assertRaises(BufferError, resize, 1) - self.assertEqual(a, orig) - - # Other operations implying resize - self.assertRaises(BufferError, a.pop, 0) - self.assertEqual(a, orig) - self.assertRaises(BufferError, a.remove, a[1]) - self.assertEqual(a, orig) - self.assertRaises(BufferError, a.append, self.outside) - self.assertEqual(a, orig) - self.assertRaises(BufferError, a.insert, 1, self.outside) - self.assertEqual(a, orig) - self.assertRaises(BufferError, a.extend, self.example) - self.assertEqual(a, orig) - - def iadd(x): - x += array.array(self.typecode, self.biggerexample) - self.assertRaises(BufferError, iadd, a) - self.assertEqual(a, orig) - - def imul(x): - x *= 3 - self.assertRaises(BufferError, imul, a) - self.assertEqual(a, orig) - - def delitem(): - del a[1] - self.assertRaises(BufferError, delitem) - self.assertEqual(a, orig) - - # deleting a non-contiguous slice - def delslice(): - del a[1:-1:2] - self.assertRaises(BufferError, delslice) - self.assertEqual(a, orig) - - # Show that releasing v releases the array for size change - v.release() - a.pop() - class StringTest(BaseTest): @@ -1221,10 +1146,6 @@ def test_alloc_overflow(self): def test_main(verbose=None): import sys - if test_support.is_jython: - # CPython specific; returns a memory address - del BaseTest.test_buffer_info - test_support.run_unittest(*tests) # verify reference counting diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 1009692a3..7e8f32199 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,4 +1,4 @@ -import sys, itertools, unittest +import sys, itertools, unittest, traceback from test import test_support import ast @@ -290,6 +290,19 @@ def test_literal_eval(self): self.assertEqual(ast.literal_eval('(True, False, None)'), (True, False, None)) self.assertRaises(ValueError, ast.literal_eval, 'foo()') + def test_uses_lineno(self): + node = ast.Module(body=[ast.Expr(value=ast.Name(id='x', ctx=ast.Load()), lineno=42)]) + node = ast.fix_missing_locations(node) + exc = None + try: + exec compile(node,'','exec') + except: + exc = traceback.format_tb(sys.exc_info()[2]) + assert exc is not None + + # can only check the last line of the stack trace: + self.assertEqual(exc[-1],' File "", line 42, in \n') + def test_main(): #XXX: AST pickling is left as a TODO for now. diff --git a/Lib/test/test_binascii_jy.py b/Lib/test/test_binascii_jy.py new file mode 100644 index 000000000..d8a0e38e4 --- /dev/null +++ b/Lib/test/test_binascii_jy.py @@ -0,0 +1,72 @@ +"""Test unicode handling in the binascii Java module.""" + +from test import test_support +from test.test_binascii import BinASCIITest +import unittest +import binascii + + +class UnicodeBinASCIITest(BinASCIITest): + + type2test = unicode + + # Create binary test data, but only 7-bit data to survive implicit unicode to str conversion. + rawdata = "The quick brown fox jumps over the lazy dog.\r\n" + rawdata += "".join(map(chr, xrange(128))) + rawdata += "\r\nHello world.\n" + + def test_base64invalid(self): + # Test base64 with random invalid characters sprinkled throughout. + # This is a copy of BinASCIITest.test_base64invalid with 256 changed to 128 where we + # generate "fillers". + + # Creating the modified test reveals a latent bug in the test as written, which is that the + # padding character "=" is/was inserted as a filler. In the original test, the location of + # that is harmless. With the change 256 to 128, it causes early termination of the + # a2b_base64 conversion (both CPython and Jython). We therefore make padding a valid + # character, excluding it from the fillers. + + MAX_BASE64 = 57 + lines = [] + for i in range(0, len(self.data), MAX_BASE64): + b = self.type2test(self.rawdata[i:i+MAX_BASE64]) + a = binascii.b2a_base64(b) + lines.append(a) + + fillers = "" + valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/" + valid += "=" # pad character also valid + for i in xrange(128): # not 256 as in BinASCIITest.test_base64invalid + c = chr(i) + if c not in valid: + fillers += c + + def addnoise(line): + noise = fillers + ratio = len(line) // len(noise) + res = "" + while line and noise: + if len(line) // len(noise) > ratio: + c, line = line[0], line[1:] + else: + c, noise = noise[0], noise[1:] + res += c + return res + noise + line + + res = "" + for line in map(addnoise, lines): + a = self.type2test(line) + b = binascii.a2b_base64(a) + res += b + self.assertEqual(res, self.rawdata) + + # Test base64 with just invalid characters, which should return + # empty strings. TBD: shouldn't it raise an exception instead ? + self.assertEqual(binascii.a2b_base64(self.type2test(fillers)), '') + + +def test_main(): + test_support.run_unittest(UnicodeBinASCIITest) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_bytecodetools_jy.py b/Lib/test/test_bytecodetools_jy.py index f67d7810d..e6409c684 100644 --- a/Lib/test/test_bytecodetools_jy.py +++ b/Lib/test/test_bytecodetools_jy.py @@ -36,32 +36,26 @@ def test_unregister(self): def faulty_callback(self, name, byte, klass): raise Exception("test exception") + def faulty_callback2(self, name, byte, klass, bogus): return def test_faulty_callback(self): - import java.lang.System as Sys - import java.io.PrintStream as PrintStream - import java.io.OutputStream as OutputStream - - class NullOutputStream(OutputStream): - def write(self, b): pass - def write(self, buf, offset, len): pass - - syserr = Sys.err - Sys.setErr(PrintStream(NullOutputStream())) - tools.register(self.faulty_callback) tools.register(self.assert_callback) tools.register(self.faulty_callback2) self.count=0 try: + # Suppress the warning otherwise produced + from org.python.core import Py + from java.util.logging import Level + level = Py.setLoggingLevel(Level.SEVERE) eval("42+1") finally: self.assertTrue(tools.unregister(self.faulty_callback)) self.assertTrue(tools.unregister(self.faulty_callback2)) self.assertTrue(tools.unregister(self.assert_callback)) - Sys.setErr(syserr) + Py.setLoggingLevel(level) self.assertEqual(self.count, 1) @@ -69,7 +63,11 @@ class ProxyDebugDirectoryTest(unittest.TestCase): """ProxyDebugDirectory used to be the only way to save proxied classes""" def setUp(self): - self.tmpdir = tempfile.mkdtemp() + tmp = tempfile.mkdtemp() + # Ensure Unicode since derived file paths are used in Java calls + if isinstance(tmp, bytes): + tmp = tmp.decode(sys.getfilesystemencoding()) + self.tmpdir = tmp def tearDown(self): test_support.rmtree(self.tmpdir) @@ -82,7 +80,7 @@ def test_set_debug_directory(self): class C(Callable): def call(self): return 47 - + self.assertEqual(C().call(), 47) proxy_dir = os.path.join(self.tmpdir, "org", "python", "proxies") # If test script is run outside of regrtest, the first path is used; @@ -93,7 +91,7 @@ def call(self): self.assertRegexpMatches( proxy_classes[0], r'\$C\$\d+.class$') - + def test_main(): test_support.run_unittest( diff --git a/Lib/test/test_bytes.py b/Lib/test/test_bytes.py index 0668d8689..732fb1a6d 100644 --- a/Lib/test/test_bytes.py +++ b/Lib/test/test_bytes.py @@ -217,7 +217,9 @@ def test_concat(self): self.assertEqual(b1 + bytes(b"def"), b"abcdef") self.assertEqual(bytes(b"def") + b1, b"defabc") self.assertRaises(TypeError, lambda: b1 + u"def") - self.assertRaises(TypeError, lambda: u"abc" + b2) + # Jython treats unicode + bytearray the same way as unicode + str + #self.assertRaises(TypeError, lambda: u"abc" + b2) + self.assertEqual(u"def" + b1, u"defabc") # OK in Jython def test_repeat(self): for b in b"abc", self.type2test(b"abc"): diff --git a/Lib/test/test_bytes_jy.py b/Lib/test/test_bytes_jy.py index 6fa0631ae..507e765f9 100644 --- a/Lib/test/test_bytes_jy.py +++ b/Lib/test/test_bytes_jy.py @@ -16,8 +16,8 @@ class Sub(bytearray): pass self.assertEqual(len(s), 6) -class SimpleOperationsTest(unittest.TestCase): - # Things the CPython library did not test throughly enough +class BytesOperationsTest(unittest.TestCase): + # Tests additional to the CPython library, on bytes/str def test_irepeat(self) : @@ -70,7 +70,7 @@ def checkequal(self, expected, obj, methodname, *args): LOWER = b'\xe0\xe7\xe9\xff' # Uppercase in Latin-1 but not ascii UPPER = b'\xc0\xc7\xc9\xdd' # Lowercase in Latin-1 but not ascii DIGIT = b'\xb9\xb2\xb3' # sup 1, 2, 3: numeric in Python (not Java) - SPACE = b'\x85\xa0' # NEXT LINE, NBSP: space in Python (not Java) + SPACE = b'\x85\xa0' # NEXT LINE, NBSP: space in unicode (not in str/bytes) def test_isalpha(self): for c in self.UPPER + self.LOWER: @@ -178,10 +178,83 @@ def test_split(self): self.assertEqual(1, len(s.rsplit()), "rsplit made in " + repr(s)) +class BufferOperationsTest(unittest.TestCase): + # Tests additional to the CPython library, on buffer + + def test_repr(self): + # Exact form of buffer.__repr__ + text = u"Le dîner à Étretat".encode('latin-1') + buf = buffer(text) + expected = r"" + self.assertRegexpMatches(repr(buf), expected) + self.assertRegexpMatches(buf.__repr__(), expected) + + def test_str(self): + # Exact form of buffer.__str__ + text = u"Le dîner à Étretat".encode('latin-1') + buf = buffer(text) + expected = text + self.assertEqual(str(buf), expected) + self.assertEqual(buf.__str__(), expected) + + def test_add_memoryview(self): + b = buffer(b"abc") + # add memoryview + c = b + memoryview('xyz') + self.assertEqual(str(c), 'abcxyz') + + def test_add_bytearray(self): + b = buffer(b"abc") + # add bytearray + b += bytearray('xyz') + self.assertEqual(str(b), 'abcxyz') + + def test_iadd_memoryview(self): + b = buffer(b"abc") + # concatenate memoryview + b += memoryview('xyz') + self.assertEqual(str(b), 'abcxyz') + + def test_iadd_bytearray(self): + b = buffer(b"abc") + # concatenate bytearray + b += bytearray('xyz') + self.assertEqual(str(b), 'abcxyz') + + +class ByteArrayTest(unittest.TestCase): + # Tests additional to the CPython library, on bytearray + + def test_add_memoryview(self): + b = bytearray(b"abc") + # add memoryview + c = b + memoryview('xyz') + self.assertEqual(str(c), 'abcxyz') + + def test_add_buffer(self): + b = bytearray(b"abc") + # add buffer + c = b + buffer('xyz') + self.assertEqual(str(c), 'abcxyz') + + def test_iadd_memoryview(self): + b = bytearray(b"abc") + # concatenate memoryview + b += memoryview('xyz') + self.assertEqual(str(b), 'abcxyz') + + def test_iadd_buffer(self): + b = bytearray(b"abc") + # concatenate buffer + b += buffer('xyz') + self.assertEqual(str(b), 'abcxyz') + def test_main(): test.test_support.run_unittest( ByteArraySubclassTest, - SimpleOperationsTest, + BytesOperationsTest, + BufferOperationsTest, + ByteArrayTest ) diff --git a/Lib/test/test_calendar_jy.py b/Lib/test/test_calendar_jy.py new file mode 100644 index 000000000..9b1c99f65 --- /dev/null +++ b/Lib/test/test_calendar_jy.py @@ -0,0 +1,24 @@ +# Java locale differences from JDK 9 onwards, and locale variation on +# developer machines, break test_calendar tests. This manifests more on Windows. +# Rather than diverge from the Python source, this overrides with extra locale +# setup. + +from test.test_calendar import * +from test import test_support + + +def test_main(initialize=True): + test_support.force_reset_locale(initialize) + test_support.run_unittest( + OutputTestCase, + CalendarTestCase, + MondayTestCase, + SundayTestCase, + MonthRangeTestCase, + LeapdaysTestCase, + ) + + +if __name__ == '__main__': + test_main(initialize=False) + diff --git a/Lib/test/test_chdir.py b/Lib/test/test_chdir.py index e2c618765..4823ac949 100644 --- a/Lib/test/test_chdir.py +++ b/Lib/test/test_chdir.py @@ -185,14 +185,47 @@ class WindowsChdirTestCase(BaseChdirTestCase): def setUp(self): super(WindowsChdirTestCase, self).setUp() - self.subdir = os.path.join(self.dir1, 'Program Files') + self.windowsTestDir = 'Program Files' + self.subdir = os.path.join(self.dir1, self.windowsTestDir) os.makedirs(self.subdir) + def shortname(self,path): + # From later versions of Windows (post-Vista), not all files and + # directories have short names + # This is set at the filesystem level and seems intended to phase + # out short (DOS) names + # https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file + # shortname.bat returns the short name if available, else the full name + shortnameLoc = test_support.findfile('shortname.bat') + output = subprocess.check_output(['cmd','/c',shortnameLoc,path]) + return output.strip() + def test_windows_chdir_dos_path(self): + output = self.shortname(self.subdir) + if output.strip().endswith(self.windowsTestDir): + self.skipTest('no dos path to test on this filesystem') dos_name = os.path.join(self.dir1, 'progra~1') os.chdir(dos_name) self.assertEqual(os.getcwd(), os.path.realpath(dos_name)) + def test_windows_chdir_dos_path_program_files(self): + # Prove that we can navigate to a commonly existing system directory + # with a shortname alias. Program Files commonly has 8dot3 (short) alias + # for script back-compatibility. Unlike other tests in the class, don't + # create a temp directory + pfileName = os.environ['PROGRAMFILES'] + shortPfileName = self.shortname( pfileName ) + if not os.path.exists(shortPfileName): + self.skipTest('Windows PROGRAMFILES short directory not found on this system') + if pfileName == shortPfileName: + self.skipTest('Windows system with PROGRAMFILES on non 8dot3 filesystem') + cwd = os.getcwd() + try: + os.chdir(pfileName) + self.assertEqual(os.getcwd(), os.path.realpath(pfileName)) + finally: + os.chdir(cwd) + def test_windows_getcwd_ensures_drive_letter(self): # subdir is in the TEMP directory, usually on C:, while the # current working directory could be (for the sake of comments) diff --git a/Lib/test/test_class_jy.py b/Lib/test/test_class_jy.py index 2c29ab1a4..3effad276 100644 --- a/Lib/test/test_class_jy.py +++ b/Lib/test/test_class_jy.py @@ -184,6 +184,19 @@ class C(A): class D(B, C): pass + def test_slotted_diamond_problem_bug_v2(self): + # see http://bugs.jython.org/issue2551 + class A(object): + __slots__ = 'foo' + class B(A): + __slots__ = 'bar' + class C(A): + __slots__ = () + # used to raise TypeError: multiple bases have instance lay-out + # conflict + class D(B, C): + pass + def test_getitem_exceptions(self): class A: def __getitem__(self, key): diff --git a/Lib/test/test_classpathimporter.py b/Lib/test/test_classpathimporter.py index c0a0e0f11..6761e44f6 100644 --- a/Lib/test/test_classpathimporter.py +++ b/Lib/test/test_classpathimporter.py @@ -26,13 +26,15 @@ def tearDown(self): # with sys.path.append where not getting scanned if they start with a top # level package we already have, like the "org" in org.python.* def test_bug1239(self): - with test_support.DirsOnSysPath("Lib/test/bug1239.jar"): + jar = test_support.findfile("bug1239.jar") + with test_support.DirsOnSysPath(jar): import org.test403javapackage.test403 # different from test_bug1239 in that only a Java package is imported, not # a Java class. I'd also like to get rid of this checked in test jar. def test_bug1126(self): - with test_support.DirsOnSysPath("Lib/test/bug1126/bug1126.jar"): + jar = test_support.findfile("bug1126.jar", subdir="bug1126") + with test_support.DirsOnSysPath(jar): import org.subpackage @@ -119,6 +121,9 @@ def test_loader_is_package(self): self.assertFalse(loader.is_package('jar_pkg.prefer_compiled')) @unittest.skipIf(test_support.is_jython_posix, "FIXME: failing on Linux issue #2422") + @unittest.skipIf(test_support.get_java_version() >= (9,), + "Fails on Java 9+. See b.j.o. issue #2362") # FIXME + # Probably related to Java modules: ensure also works outside java.base def test_loader_get_code(self): # Execute Python code out of the JAR jar = self.prepareJar('classimport.jar') diff --git a/Lib/test/test_cmd_line.py b/Lib/test/test_cmd_line.py index 26d1f03ad..84c02a95a 100644 --- a/Lib/test/test_cmd_line.py +++ b/Lib/test/test_cmd_line.py @@ -1,37 +1,32 @@ -import os -import test.test_support, unittest +# Tests invocation of the interpreter with various command line arguments +# All tests are executed with environment variables ignored +# See test_cmd_line_script.py for testing of script execution + +import test.test_support import sys -import popen2 -import subprocess +import unittest +from test.script_helper import ( + assert_python_ok, assert_python_failure, spawn_python, kill_python, + python_exit_code +) + class CmdLineTest(unittest.TestCase): @classmethod def tearDownClass(cls): if test.test_support.is_jython: - # GC is not immediate, so if Popen.__del__ may be delayed. + # GC is not immediate, so Popen.__del__ may be delayed. # Try to force any Popen.__del__ errors within scope of test. from test_weakref import extra_collect extra_collect() - def start_python(self, cmd_line): - outfp, infp = popen2.popen4('"%s" %s' % (sys.executable, cmd_line)) - infp.close() - data = outfp.read() - outfp.close() - # try to cleanup the child so we don't appear to leak when running - # with regrtest -R. This should be a no-op on Windows. - popen2._cleanup() - return data + def start_python(self, *args): + p = spawn_python(*args) + return kill_python(p) def exit_code(self, *args): - cmd_line = [sys.executable] - cmd_line.extend(args) - devnull = open(os.devnull, 'w') - result = subprocess.call(cmd_line, stdout=devnull, - stderr=subprocess.STDOUT) - devnull.close() - return result + return python_exit_code(*args) def test_directories(self): self.assertNotEqual(self.exit_code('.'), 0) @@ -40,10 +35,7 @@ def test_directories(self): def verify_valid_flag(self, cmd_line): data = self.start_python(cmd_line) self.assertTrue(data == '' or data.endswith('\n')) - self.assertTrue('Traceback' not in data) - - def test_environment(self): - self.verify_valid_flag('-E') + self.assertNotIn('Traceback', data) def test_optimize(self): self.verify_valid_flag('-O') @@ -59,14 +51,12 @@ def test_site_flag(self): self.verify_valid_flag('-S') def test_usage(self): - self.assertTrue('usage' in self.start_python('-h')) + self.assertIn('usage', self.start_python('-h')) def test_version(self): - prefix = 'J' if test.test_support.is_jython else 'P' - version = prefix + 'ython %d.%d' % sys.version_info[:2] - start = self.start_python('-V') - self.assertTrue(start.startswith(version), - "%s does not start with %s" % (start, version)) + prefix = 'Jython' if test.test_support.is_jython else 'Python' + version = (prefix + ' %d.%d') % sys.version_info[:2] + self.assertTrue(self.start_python('-V').startswith(version)) def test_run_module(self): # Test expected operation of the '-m' switch @@ -86,6 +76,17 @@ def test_run_module(self): self.exit_code('-m', 'timeit', '-n', '1'), 0) + def test_run_module_bug1764407(self): + # -m and -i need to play well together + # Runs the timeit module and checks the __main__ + # namespace has been populated appropriately + p = spawn_python('-i', '-m', 'timeit', '-n', '1') + p.stdin.write('Timer\n') + p.stdin.write('exit()\n') + data = kill_python(p) + self.assertTrue(data.startswith('1 loop')) + self.assertIn('__main__.Timer', data) + def test_run_code(self): # Test expected operation of the '-c' switch # Switch needs an argument @@ -99,6 +100,91 @@ def test_run_code(self): self.exit_code('-c', 'pass'), 0) + @unittest.skipIf(test.test_support.is_jython, + "Hash randomisation is not supported in Jython.") + def test_hash_randomization(self): + # Verify that -R enables hash randomization: + self.verify_valid_flag('-R') + hashes = [] + for i in range(2): + code = 'print(hash("spam"))' + data = self.start_python('-R', '-c', code) + hashes.append(data) + self.assertNotEqual(hashes[0], hashes[1]) + + # Verify that sys.flags contains hash_randomization + code = 'import sys; print sys.flags' + data = self.start_python('-R', '-c', code) + self.assertTrue('hash_randomization=1' in data) + + def test_del___main__(self): + # Issue #15001: PyRun_SimpleFileExFlags() did crash because it kept a + # borrowed reference to the dict of __main__ module and later modify + # the dict whereas the module was destroyed + filename = test.test_support.TESTFN + self.addCleanup(test.test_support.unlink, filename) + with open(filename, "w") as script: + print >>script, "import sys" + print >>script, "del sys.modules['__main__']" + assert_python_ok(filename) + + def test_unknown_options(self): + rc, out, err = assert_python_failure('-E', '-z') + self.assertIn(b'Unknown option: -z', err) + self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) + self.assertEqual(b'', out) + # Add "without='-E'" to prevent _assert_python to append -E + # to env_vars and change the output of stderr + rc, out, err = assert_python_failure('-z', without='-E') + self.assertIn(b'Unknown option: -z', err) + self.assertEqual(err.splitlines().count(b'Unknown option: -z'), 1) + self.assertEqual(b'', out) + rc, out, err = assert_python_failure('-a', '-z', without='-E') + self.assertIn(b'Unknown option: -a', err) + # only the first unknown option is reported + self.assertNotIn(b'Unknown option: -z', err) + self.assertEqual(err.splitlines().count(b'Unknown option: -a'), 1) + self.assertEqual(b'', out) + + def test_python_startup(self): + # Test that the file designated by [PJ]YTHONSTARTUP is executed when interactive. + # Note: this test depends on the -i option forcing Python to treat stdin as interactive. + filename = test.test_support.TESTFN + self.addCleanup(test.test_support.unlink, filename) + with open(filename, "w") as script: + print >>script, "print 6*7" + print >>script, "print 'Ni!'" + expected = ['42', 'Ni!'] + def check(*args, **kwargs): + result = assert_python_ok(*args, **kwargs) + self.assertListEqual(expected, result[1].splitlines()) + if test.test_support.is_jython: + # Jython produces a prompt before exit, but not CPython. Hard to say who is correct. + expected.append('>>> ') + # The Jython way is to set a registry item python.startup + check('-i', '-J-Dpython.startup={}'.format(filename)) + # But a JYTHONSTARTUP environment variable is also supported + check('-i', JYTHONSTARTUP=filename) + else: + check('-i', PYTHONSTARTUP=filename) + + @unittest.skipUnless(test.test_support.is_jython, "Requires write to sys.flags.inspect") + def test_python_inspect(self): + # Test that PYTHONINSPECT set during a script causes an interactive session to start. + # Note: this test depends on the -i option forcing Python to treat stdin as interactive, + # and on Jython permitting manipulation of sys.flags.inspect (which CPython won't) + # so that PYTHONINSPECT can have some effect. + filename = test.test_support.TESTFN + self.addCleanup(test.test_support.unlink, filename) + with open(filename, "w") as script: + print >>script, "import sys, os" + print >>script, "sys.flags.inspect = False" + print >>script, "os.environ['PYTHONINSPECT'] = 'whatever'" + print >>script, "print os.environ['PYTHONINSPECT']" + expected = ['whatever', '>>> '] + result = assert_python_ok('-i', filename) + self.assertListEqual(expected, result[1].splitlines()) + def test_main(): test.test_support.run_unittest(CmdLineTest) diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py deleted file mode 100644 index 872fd1cdd..000000000 --- a/Lib/test/test_cmd_line_script.py +++ /dev/null @@ -1,224 +0,0 @@ -# Tests command line execution of scripts - -import unittest -import os -import os.path -import test.test_support -from test.script_helper import (run_python, - temp_dir, make_script, compile_script, - make_pkg, make_zip_script, make_zip_pkg) -from test.test_support import is_jython - -verbose = test.test_support.verbose - - -test_source = """\ -# Script may be run with optimisation enabled, so don't rely on assert -# statements being executed -def assertEqual(lhs, rhs): - if lhs != rhs: - raise AssertionError('%r != %r' % (lhs, rhs)) -def assertIdentical(lhs, rhs): - if lhs is not rhs: - raise AssertionError('%r is not %r' % (lhs, rhs)) -# Check basic code execution -result = ['Top level assignment'] -def f(): - result.append('Lower level reference') -f() -assertEqual(result, ['Top level assignment', 'Lower level reference']) -# Check population of magic variables -assertEqual(__name__, '__main__') -print '__file__==%r' % __file__ -print '__package__==%r' % __package__ -# Check the sys module -import sys -assertIdentical(globals(), sys.modules[__name__].__dict__) -print 'sys.argv[0]==%r' % sys.argv[0] -""" - -def _make_test_script(script_dir, script_basename, source=test_source): - return make_script(script_dir, script_basename, source) - -def _make_test_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, - source=test_source, depth=1): - return make_zip_pkg(zip_dir, zip_basename, pkg_name, script_basename, - source, depth) - -# There's no easy way to pass the script directory in to get -# -m to work (avoiding that is the whole point of making -# directories and zipfiles executable!) -# So we fake it for testing purposes with a custom launch script -launch_source = """\ -import sys, os.path, runpy -sys.path.insert(0, %s) -runpy._run_module_as_main(%r) -""" - -def _make_launch_script(script_dir, script_basename, module_name, path=None): - if path is None: - path = "os.path.dirname(__file__)" - else: - path = repr(path) - source = launch_source % (path, module_name) - return make_script(script_dir, script_basename, source) - -class CmdLineTest(unittest.TestCase): - def _check_script(self, script_name, expected_file, - expected_argv0, expected_package, - *cmd_line_switches): - run_args = cmd_line_switches + (script_name,) - exit_code, data = run_python(*run_args) - if verbose: - print 'Output from test script %r:' % script_name - print data - self.assertEqual(exit_code, 0) - printed_file = '__file__==%r' % str(expected_file) - printed_argv0 = 'sys.argv[0]==%r' % str(expected_argv0) - printed_package = '__package__==%r' % (str(expected_package) if expected_package is not None else expected_package) - if verbose: - print 'Expected output:' - print printed_file - print printed_package - print printed_argv0 - self.assertIn(printed_file, data) - self.assertIn(printed_package, data) - self.assertIn(printed_argv0, data) - - def _check_import_error(self, script_name, expected_msg, - *cmd_line_switches): - run_args = cmd_line_switches + (script_name,) - exit_code, data = run_python(*run_args) - if verbose: - print 'Output from test script %r:' % script_name - print data - print 'Expected output: %r' % expected_msg - self.assertIn(expected_msg, data) - - def test_basic_script(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, 'script') - self._check_script(script_name, script_name, script_name, None) - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_script_compiled(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, 'script') - compiled_name = compile_script(script_name) - os.remove(script_name) - self._check_script(compiled_name, compiled_name, compiled_name, None) - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_directory(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, '__main__') - self._check_script(script_dir, script_name, script_dir, '') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_directory_compiled(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, '__main__') - compiled_name = compile_script(script_name) - os.remove(script_name) - self._check_script(script_dir, compiled_name, script_dir, '') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_directory_error(self): - with temp_dir() as script_dir: - msg = "can't find '__main__' module in %r" % script_dir - self._check_import_error(script_dir, msg) - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_zipfile(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, '__main__') - zip_name, run_name = make_zip_script(script_dir, 'test_zip', script_name) - self._check_script(zip_name, run_name, zip_name, '') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_zipfile_compiled(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, '__main__') - compiled_name = compile_script(script_name) - zip_name, run_name = make_zip_script(script_dir, 'test_zip', compiled_name) - self._check_script(zip_name, run_name, zip_name, '') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_zipfile_error(self): - with temp_dir() as script_dir: - script_name = _make_test_script(script_dir, 'not_main') - zip_name, run_name = make_zip_script(script_dir, 'test_zip', script_name) - msg = "can't find '__main__' module in %r" % zip_name - self._check_import_error(zip_name, msg) - - def test_module_in_package(self): - with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - script_name = _make_test_script(pkg_dir, 'script') - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script') - self._check_script(launch_name, script_name, script_name, 'test_pkg') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_module_in_package_in_zipfile(self): - with temp_dir() as script_dir: - zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script') - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.script', zip_name) - self._check_script(launch_name, run_name, run_name, 'test_pkg') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_module_in_subpackage_in_zipfile(self): - with temp_dir() as script_dir: - zip_name, run_name = _make_test_zip_pkg(script_dir, 'test_zip', 'test_pkg', 'script', depth=2) - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg.test_pkg.script', zip_name) - self._check_script(launch_name, run_name, run_name, 'test_pkg.test_pkg') - - def test_package(self): - with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - script_name = _make_test_script(pkg_dir, '__main__') - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') - self._check_script(launch_name, script_name, - script_name, 'test_pkg') - - @unittest.skipIf(is_jython, "FIXME: not working in Jython") - def test_package_compiled(self): - with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - script_name = _make_test_script(pkg_dir, '__main__') - compiled_name = compile_script(script_name) - os.remove(script_name) - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') - self._check_script(launch_name, compiled_name, - compiled_name, 'test_pkg') - - def test_package_error(self): - with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - msg = ("'test_pkg' is a package and cannot " - "be directly executed") - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') - self._check_import_error(launch_name, msg) - - def test_package_recursion(self): - with temp_dir() as script_dir: - pkg_dir = os.path.join(script_dir, 'test_pkg') - make_pkg(pkg_dir) - main_dir = os.path.join(pkg_dir, '__main__') - make_pkg(main_dir) - msg = ("Cannot use package as __main__ module; " - "'test_pkg' is a package and cannot " - "be directly executed") - launch_name = _make_launch_script(script_dir, 'launch', 'test_pkg') - self._check_import_error(launch_name, msg) - - -def test_main(): - test.test_support.run_unittest(CmdLineTest) - test.test_support.reap_children() - -if __name__ == '__main__': - test_main() diff --git a/Lib/test/test_codecencodings_tw.py b/Lib/test/test_codecencodings_tw.py new file mode 100644 index 000000000..a536990b4 --- /dev/null +++ b/Lib/test/test_codecencodings_tw.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# +# test_codecencodings_tw.py +# Codec encoding tests for ROC encodings. +# + +from test import test_support +from test import test_multibytecodec_support +import unittest +import sys + +# Codecs re-synchronise faster after illegal byte in Java 8+ than in Java 7 to +# update 60 (and in CPython 3.3+ faster than in CPython 2.7-3.2). Either is +# correct, but we need to know which one to expect. +RESYNC_FASTER = False # True for CPython 3.3 and later + +if sys.platform.startswith('java'): + if test_support.get_java_version() > (1, 7, 0, 60): + RESYNC_FASTER = True + + +class Test_Big5(test_multibytecodec_support.TestBase, unittest.TestCase): + encoding = 'big5' + tstring = test_multibytecodec_support.load_teststring('big5') + if RESYNC_FASTER: + # Version from CPython 3.6 where \0x80\0x80 is two invalid sequences. + # Java 8 agrees with this interpretation. + codectests = ( + # invalid bytes + (b"abc\x80\x80\xc1\xc4", "strict", None), + (b"abc\xc8", "strict", None), + (b"abc\x80\x80\xc1\xc4", "replace", u"abc\ufffd\ufffd\u8b10"), + (b"abc\x80\x80\xc1\xc4\xc8", "replace", u"abc\ufffd\ufffd\u8b10\ufffd"), + (b"abc\x80\x80\xc1\xc4", "ignore", u"abc\u8b10"), + ) + else: + # Standard version of test from CPython 2.7 + codectests = ( + # invalid bytes + ("abc\x80\x80\xc1\xc4", "strict", None), + ("abc\xc8", "strict", None), + ("abc\x80\x80\xc1\xc4", "replace", u"abc\ufffd\u8b10"), + ("abc\x80\x80\xc1\xc4\xc8", "replace", u"abc\ufffd\u8b10\ufffd"), + ("abc\x80\x80\xc1\xc4", "ignore", u"abc\u8b10"), + ) + +def test_main(): + test_support.run_unittest(__name__) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_codecs_jy.py b/Lib/test/test_codecs_jy.py index 1e576a8e5..63bc6ae8a 100644 --- a/Lib/test/test_codecs_jy.py +++ b/Lib/test/test_codecs_jy.py @@ -6,13 +6,11 @@ class CodecsTestCase(unittest.TestCase): def test_print_sans_lib(self): - """Encodes and decodes using utf-8 after in an environment - without the standard library - - Checks that the builtin utf-8 codec is always available: - http://bugs.jython.org/issue1458""" + # Encode and decode using utf-8 in an environment without the standard + # library, to check that a utf-8 codec is always available. See: + # http://bugs.jython.org/issue1458 subprocess.call([sys.executable, "-J-Dpython.cachedir.skip=true", - "-J-Dpython.security.respectJavaAccessibility=false", + "-S", # No site module: avoid codec registry initialised too soon test_support.findfile('print_sans_lib.py')]) def test_string_escape_1502(self): diff --git a/Lib/test/test_concat_jy.py b/Lib/test/test_concat_jy.py index 2c1dd3d06..650b72d56 100644 --- a/Lib/test/test_concat_jy.py +++ b/Lib/test/test_concat_jy.py @@ -23,11 +23,10 @@ class u(unicode): resType = unicode res = a.__add__(b) self.assertEquals(type(res), resType, - '%r is a %s, not a %s' % (res, type(res), - resType)) + '%r + %r -> %r is a %s, not a %s' % + (type(a), type(b), res, type(res), resType)) self.assertEquals(res, 'ab', - '%r (%s) != %r (%s)' % (res, type(res), 'ab', - str)) + '%r (%s) != %r (%s)' % (res, type(res), 'ab', str)) class StrUnicodeConcatOverridesTestCase(unittest.TestCase): diff --git a/Lib/test/test_csv_jy.py b/Lib/test/test_csv_jy.py new file mode 100644 index 000000000..e2f53edf1 --- /dev/null +++ b/Lib/test/test_csv_jy.py @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2017 Jython Developers + +# Additional csv module unit tests for Jython + +import csv +import io +import sys +from tempfile import TemporaryFile +from test import test_support +import unittest + +# This test has been adapted from Python 3 test_csv.TestUnicode. In Python 3, +# the csv module supports Unicode directly. In Python 2, it does not, except +# that it is transparent to byte data. Many tools, however, accept UTF-8 +# encoded text in a CSV file. +# +class EncodingContext(object): + """Context manager to save and restore the encoding. + + Use like this: + + with EncodingContext("utf-8"): + self.assertEqual("'caf\xc3\xa9'", u"'caf\xe9'") + """ + + def __init__(self, encoding): + if not hasattr(sys, "setdefaultencoding"): + reload(sys) + self.original_encoding = sys.getdefaultencoding() + sys.setdefaultencoding(encoding) + + def __enter__(self): + return self + + def __exit__(self, *ignore_exc): + sys.setdefaultencoding(self.original_encoding) + +class TestUnicode(unittest.TestCase): + + names = [u"Martin von Löwis", + u"Marc André Lemburg", + u"Guido van Rossum", + u"François Pinard", + u"稲田直樹"] + + def test_decode_read(self): + # The user code receives byte data and takes care of the decoding + with TemporaryFile("w+b") as fileobj: + line = u",".join(self.names) + u"\r\n" + fileobj.write(line.encode('utf-8')) + fileobj.seek(0) + reader = csv.reader(fileobj) + # The reader yields rows of byte strings that decode to the data + table = [[e.decode('utf-8') for e in row] for row in reader] + self.assertEqual(table, [self.names]) + + def test_encode_write(self): + # The user encodes unicode objects to byte data that csv writes + with TemporaryFile("w+b") as fileobj: + writer = csv.writer(fileobj) + # We present a row of encoded strings to the writer + writer.writerow([n.encode('utf-8') for n in self.names]) + # We expect the file contents to be the UTF-8 of the csv data + expected = u",".join(self.names) + u"\r\n" + fileobj.seek(0) + self.assertEqual(fileobj.read().decode('utf-8'), expected) + + def test_unicode_write(self): + # The user supplies unicode data that csv.writer default-encodes + # (undocumented feature relied upon by client code). + # See Issue #2632 https://github.com/jythontools/jython/issues/90 + with TemporaryFile("w+b") as fileobj: + with EncodingContext('utf-8'): + writer = csv.writer(fileobj) + # We present a row of unicode strings to the writer + writer.writerow(self.names) + # We expect the file contents to be the UTF-8 of the csv data + expected = u",".join(self.names) + u"\r\n" + fileobj.seek(0) + self.assertEqual(fileobj.read().decode(), expected) + + +def test_main(): + # We'll be enabling sys.setdefaultencoding so remember to disable + had_set = hasattr(sys, "setdefaultencoding") + try: + test_support.run_unittest( + TestUnicode, + ) + finally: + if not had_set: + delattr(sys, "setdefaultencoding") + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_datetime_jy.py b/Lib/test/test_datetime_jy.py index ccbd5f86b..96e5f62f4 100644 --- a/Lib/test/test_datetime_jy.py +++ b/Lib/test/test_datetime_jy.py @@ -6,7 +6,7 @@ from datetime import time from datetime import date, datetime -from java.util import Calendar, GregorianCalendar +from java.util import Calendar, GregorianCalendar, TimeZone from java.sql import Date, Time, Timestamp @@ -109,7 +109,12 @@ def test_date(self): x = date(2007, 1, 3) y = x.__tojava__(Date) self.assertIsInstance(y, Date) - self.assertEqual(y.getTime(), (x - date(1970, 1, 1)).total_seconds() * 1000) + # Note that java.sql.Date operates regarding to default timezone, so adjust offset + off = TimeZone.getDefault().getRawOffset() + # It's sufficient for the date to fit; we modulo away the time, so this test + # won't run into TimeZone issues. + self.assertEqual((y.getTime()+off)//(1000*60*60*24), + (x - date(1970, 1, 1)).total_seconds()//(60*60*24)) def test_time(self): self.assertTrue(hasattr(time, "__tojava__")) diff --git a/Lib/test/test_defaultdict_jy.py b/Lib/test/test_defaultdict_jy.py index 9c986a8d4..3fa4561dd 100644 --- a/Lib/test/test_defaultdict_jy.py +++ b/Lib/test/test_defaultdict_jy.py @@ -99,9 +99,19 @@ def tester(): for i in xrange(size): self.assertEqual(counters[i].get(), i, counters) -class GetVariantsTestCase(unittest.TestCase): - #http://bugs.jython.org/issue2133 +class UnhashableKeyRaiseTypeErrorTestCase(unittest.TestCase): + # http://bugs.jython.org/issue2522 + + def test_setitem_raises_typeerror(self): + self.assertRaises(TypeError, defaultdict(int).__setitem__, {}, 1) + + def test_getitem_raises_typeerror(self): + self.assertRaises(TypeError, defaultdict(int).__getitem__, {}) + + +class GetVariantsTestCase(unittest.TestCase): + # http://bugs.jython.org/issue2133 def test_get_does_not_vivify(self): d = defaultdict(list) @@ -119,6 +129,33 @@ def test_getitem_does_vivify(self): self.assertEquals(d.items(), [("vivify", [])]) +class GetItemPropagateWhateverMissingRaisedTestCase(unittest.TestCase): + # http://bugs.jython.org/issue2523 + + def test_getitem_propagate_default_factory_raises(self): + + class FooError(Exception): + pass + + def defaultfactory(): + raise FooError() + + d = defaultdict(defaultfactory) + self.assertRaises(FooError, d.__getitem__, 'bar') + + def test_getitem_propagate_overridden_missing_raises(self): + + class FooError(Exception): + pass + + class DefaultDict(defaultdict): + + def __missing__(self, key): + raise FooError() + + d = DefaultDict(int) + self.assertRaises(FooError, d.__getitem__, 'bar') + class OverrideMissingTestCase(unittest.TestCase): class KeyDefaultDict(defaultdict): @@ -137,7 +174,8 @@ def double(cls, k): return k + k def setUp(self): - self.kdd = OverrideMissingTestCase.KeyDefaultDict(OverrideMissingTestCase.KeyDefaultDict.double) + self.kdd = OverrideMissingTestCase.KeyDefaultDict( + OverrideMissingTestCase.KeyDefaultDict.double) def test_dont_call_derived_missing(self): self.kdd[3] = 5 @@ -151,7 +189,10 @@ def test_override_missing(self): def test_main(): - test_support.run_unittest(PickleTestCase, ThreadSafetyTestCase, GetVariantsTestCase, OverrideMissingTestCase) + test_support.run_unittest(PickleTestCase, ThreadSafetyTestCase, + UnhashableKeyRaiseTypeErrorTestCase, + GetVariantsTestCase, OverrideMissingTestCase, + GetItemPropagateWhateverMissingRaisedTestCase) if __name__ == '__main__': diff --git a/Lib/test/test_dict.py b/Lib/test/test_dict.py index 293c17db3..a8921e6f2 100644 --- a/Lib/test/test_dict.py +++ b/Lib/test/test_dict.py @@ -1,7 +1,5 @@ import unittest from test import test_support -from java.util import Map -from java.util.concurrent import ConcurrentMap import UserDict, random, string import gc, weakref @@ -9,10 +7,14 @@ class DictTest(unittest.TestCase): - _class = None + type2test = dict def _make_dict(self, pydict): - return pydict if not self._class else self._class(pydict) + 'Create a self.type2test from pydict, or just return it if we are testing dict' + if self.type2test is dict: + return pydict + else: + return self.type2test(pydict) def test_constructor(self): # calling built-in types without argument must return empty @@ -217,7 +219,10 @@ def next(self): self.assertRaises(ValueError, d.update, [(1, 2, 3)]) def test_fromkeys(self): - self.assertEqual(dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + Dict = self.type2test + + self.assertEqual(Dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + d = self._make_dict({}) self.assertIsNot(d.fromkeys('abc'), d) self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) @@ -226,23 +231,25 @@ def test_fromkeys(self): def g(): yield 1 self.assertEqual(d.fromkeys(g()), {1:None}) - self.assertRaises(TypeError, {}.fromkeys, 3) - class dictlike(dict): pass + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3) + + class dictlike(Dict): pass self.assertEqual(dictlike.fromkeys('a'), {'a':None}) self.assertEqual(dictlike().fromkeys('a'), {'a':None}) self.assertIsInstance(dictlike.fromkeys('a'), dictlike) self.assertIsInstance(dictlike().fromkeys('a'), dictlike) - class mydict(dict): + + class mydict(Dict): def __new__(cls): return UserDict.UserDict() ud = mydict.fromkeys('ab') self.assertEqual(ud, {'a':None, 'b':None}) self.assertIsInstance(ud, UserDict.UserDict) - self.assertRaises(TypeError, dict.fromkeys) + self.assertRaises(TypeError, Dict.fromkeys) class Exc(Exception): pass - class baddict1(dict): + class baddict1(Dict): def __init__(self): raise Exc() @@ -254,17 +261,25 @@ def __iter__(self): def next(self): raise Exc() - self.assertRaises(Exc, dict.fromkeys, BadSeq()) + self.assertRaises(Exc, Dict.fromkeys, BadSeq()) - class baddict2(dict): + class baddict2(Dict): def __setitem__(self, key, value): raise Exc() self.assertRaises(Exc, baddict2.fromkeys, [1]) # test fast path for dictionary inputs - d = dict(zip(range(6), range(6))) - self.assertEqual(dict.fromkeys(d, 0), dict(zip(range(6), [0]*6))) + d = Dict(zip(range(6), range(6))) + self.assertEqual(Dict.fromkeys(d, 0), Dict(zip(range(6), [0]*6))) + + class baddict3(Dict): + def __new__(cls): + return d + d = self._make_dict({i : i for i in range(10)}) + res = d.copy() + res.update(a=None, b=None, c=None) + self.assertEqual(baddict3.fromkeys({"a", "b", "c"}), res) def test_copy(self): d = self._make_dict({1:1, 2:2, 3:3}) @@ -312,6 +327,7 @@ def __hash__(self): x.fail = True self.assertRaises(Exc, d.setdefault, x, []) + @unittest.skipIf(test_support.is_jython, "CPython specific. See bjo issue 2711.") def test_setdefault_atomic(self): # Issue #13521: setdefault() calls __hash__ and __eq__ only once. class Hashed(object): @@ -326,8 +342,6 @@ def __eq__(self, other): return id(self) == id(other) hashed1 = Hashed() y = self._make_dict({hashed1: 5}) - if isinstance(y, Map) and not isinstance(y, ConcurrentMap): - raise unittest.SkipTest("java.util.Map objects that do not implement ConcurrentMap have no concurrency guarantees") # given that there are potentially multiple copies of the # above dict in self._make_dict, record the hash_count so it # can be subtracted out @@ -452,15 +466,16 @@ def __hash__(self): d1 < d2 def test_missing(self): + Dict = self.type2test # Make sure dict doesn't have a __missing__ method - self.assertFalse(hasattr(dict, "__missing__")) + self.assertFalse(hasattr(Dict, "__missing__")) self.assertFalse(hasattr(self._make_dict({}), "__missing__")) # Test several cases: # (D) subclass defines __missing__ method returning a value # (E) subclass defines __missing__ method raising RuntimeError # (F) subclass sets __missing__ instance variable (no effect) # (G) subclass doesn't define __missing__ at a all - class D(dict): + class D(Dict): def __missing__(self, key): return 42 d = D({1: 2, 3: 4}) @@ -470,7 +485,7 @@ def __missing__(self, key): self.assertNotIn(2, d.keys()) self.assertEqual(d[2], 42) - class E(dict): + class E(Dict): def __missing__(self, key): raise RuntimeError(key) e = E() @@ -478,7 +493,7 @@ def __missing__(self, key): e[42] self.assertEqual(c.exception.args, (42,)) - class F(dict): + class F(Dict): def __init__(self): # An instance variable __missing__ should have no effect self.__missing__ = lambda key: None @@ -487,7 +502,7 @@ def __init__(self): f[42] self.assertEqual(c.exception.args, (42,)) - class G(dict): + class G(Dict): pass g = G() with self.assertRaises(KeyError) as c: @@ -577,15 +592,18 @@ def test_empty_presized_dict_in_freelist(self): 'f': None, 'g': None, 'h': None}) d = {} + @unittest.skipIf(test_support.is_jython, "CPython specific (garbage collection).") def test_container_iterator(self): # Bug #3680: tp_traverse was not implemented for dictiter objects + Dict = self.type2test class C(object): pass - iterators = (dict.iteritems, dict.itervalues, dict.iterkeys) + #iterators = (lambda c: c.iteritems, lambda c: c.itervalues, lambda c: c.iterkeys) + iterators = (Dict.iteritems, Dict.itervalues, Dict.iterkeys) for i in iterators: obj = C() ref = weakref.ref(obj) - container = {obj: 1} + container = self._make_dict({obj: 1}) obj.x = i(container) del obj, container gc.collect() @@ -692,11 +710,6 @@ class MyDict(dict): pass self._tracked(MyDict()) - def test_list_equality(self): - class A(dict): pass - for dtype in (A, dict): - self.assertEquals([dtype()], [dict()]) - from test import mapping_tests diff --git a/Lib/test/test_dict_jy.py b/Lib/test/test_dict_jy.py index 2c78d7add..9137672f4 100644 --- a/Lib/test/test_dict_jy.py +++ b/Lib/test/test_dict_jy.py @@ -1,10 +1,16 @@ from test import test_support -from java.util import HashMap, Hashtable import unittest +import UserDict from collections import defaultdict import test_dict +from java.util import HashMap, LinkedHashMap, Hashtable +from java.util.concurrent import ConcurrentHashMap +from org.python.core import PyStringMap as stringmap + + class DictInitTest(unittest.TestCase): + def testInternalSetitemInInit(self): """Test for http://jython.org/bugs/1816134 @@ -41,14 +47,17 @@ def testUnhashableKeys(self): else: self.fail("dict as dict key should raise TypeError") + class DictCmpTest(unittest.TestCase): "Test for http://bugs.jython.org/issue1031" + def testDictCmp(self): # 'Implicit' comparision of dicts against other types instances # shouldn't raise exception: self.assertNotEqual({}, '') # The same, but explicitly calling __cmp__ should raise TypeError: self.assertRaises(TypeError, {}.__cmp__, '') + def testDictDerivedCmp(self): # With derived classes that doesn't override __cmp__, the behaviour # should be the same that with dicts: @@ -86,7 +95,9 @@ class yet_another_dict(derived_dict_with_custom_cmp): pass self.assertEqual(derived_dict_with_custom_cmp(), '') self.assertEqual(yet_another_dict(), '') + class DictMiscTest(unittest.TestCase): + def test_pop_key_error(self): # tests http://bugs.jython.org/issue2247 with self.assertRaisesRegexp(KeyError, r"^1$"): @@ -96,8 +107,10 @@ def test_pop_key_error(self): with self.assertRaisesRegexp(KeyError, r"^frozenset\(\[\]\)$"): {}.pop(frozenset()) + class DerivedDictTest(unittest.TestCase): "Tests for derived dict behaviour" + def test_raising_custom_key_error(self): class CustomKeyError(KeyError): pass @@ -105,7 +118,7 @@ class DerivedDict(dict): def __getitem__(self, key): raise CustomKeyError("custom message") self.assertRaises(CustomKeyError, lambda: DerivedDict()['foo']) - + def test_issue1676(self): #See http://bugs.jython.org/issue1676 x=defaultdict() @@ -123,8 +136,11 @@ def test_big_dict(self): class JavaIntegrationTest(unittest.TestCase): "Tests for instantiating dicts from Java maps and hashtables" - def test_hashmap(self): - x = HashMap() + + type2test = HashMap + + def test_map(self): + x = self.type2test() x.put('a', 1) x.put('b', 2) x.put('c', 3) @@ -132,8 +148,8 @@ def test_hashmap(self): y = dict(x) self.assertEqual(set(y.items()), set([('a', 1), ('b', 2), ('c', 3), ((1,2), "xyz")])) - def test_hashmap_builtin_pymethods(self): - x = HashMap() + def test_map_builtin_pymethods(self): + x = self.type2test() x['a'] = 1 x[(1, 2)] = 'xyz' self.assertEqual({tup for tup in x.iteritems()}, {('a', 1), ((1, 2), 'xyz')}) @@ -142,52 +158,119 @@ def test_hashmap_builtin_pymethods(self): self.assertEqual(str(x), repr(x)) self.assertEqual(type(str(x)), type(repr(x))) - def test_hashtable_equal(self): + def test_equal(self): for d in ({}, {1:2}): - x = Hashtable(d) + x = self.type2test(d) self.assertEqual(x, d) self.assertEqual(d, x) self.assertEqual(x, HashMap(d)) - def test_hashtable_remove(self): - x = Hashtable({}) + def test_remove(self): + x = self.type2test({'a': 1}) + del x['a'] + self.assertEqual(x, {}) + + x = self.type2test({}) with self.assertRaises(KeyError): del x[0] - def test_hashtable(self): - x = Hashtable() - x.put('a', 1) - x.put('b', 2) - x.put('c', 3) - x.put((1,2), "xyz") - y = dict(x) - self.assertEqual(set(y.items()), set([('a', 1), ('b', 2), ('c', 3), ((1,2), "xyz")])) + def test_equality_empty_dict(self): + jmap = self.type2test() + self.assertTrue(jmap == {}) + self.assertTrue({} == jmap) + + def test_equality_simple_dict(self): + jmap = self.type2test() + self.assertFalse({'a': 1} == jmap) + self.assertFalse(jmap == {'a': 1}) + + def test_equality_mixed_types_dict(self): + ref = {False:0, 'a':1, u'b':2L, 3:"3"} + alt = {0:False, u'a':True, 'b':2, 3:"3"} + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + for v in [ref, alt, jref]: + self.assertTrue(jref == v) + self.assertTrue(v == jref) + self.assertTrue(jref == self.type2test(v)) + self.assertTrue(self.type2test(v) == jref) + + alt1 = ref.copy(); alt1['a'] = 2; + alt2 = ref.copy(); del alt2['a']; + alt3 = ref.copy(); alt3['c'] = []; + for v in [alt1, alt2, alt3, {}]: + self.assertFalse(jref == v) + self.assertFalse(v == jref) + self.assertFalse(jref == self.type2test(v)) + self.assertFalse(self.type2test(v) == jref) + + # Test for http://bugs.jython.org/issue2639 + # This is to test the != comparisons between Java and Python maps/dict + def test_inequality_empty_dict(self): + jmap = self.type2test() + self.assertFalse(jmap != {}) + self.assertFalse({} != jmap) + + def test_inequality_simple_dict(self): + jmap = self.type2test() + self.assertTrue(jmap != {'a': 1}) + self.assertTrue({'a': 1} != jmap) + + def test_inequality_mixed_types_dict(self): + ref = {False:0, 'a':1, u'b':2L, 3:"3"} + alt = {0:False, u'a':True, 'b':2, 3:"3"} + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + for v in [ref, alt, jref]: + self.assertFalse(jref != v) + self.assertFalse(v != jref) + self.assertFalse(jref != self.type2test(v)) + self.assertFalse(self.type2test(v) != jref) + + alt1 = ref.copy(); alt1['a'] = 2; + alt2 = ref.copy(); del alt2['a']; + alt3 = ref.copy(); alt3['c'] = []; + for v in [alt1, alt2, alt3, {}]: + self.assertTrue(jref != v) + self.assertTrue(v != jref) + self.assertTrue(jref != self.type2test(v)) + self.assertTrue(self.type2test(v) != jref) + + +class JavaHashMapTest(JavaIntegrationTest): + type2test = HashMap + +class JavaLinkedHashMapTest(JavaIntegrationTest): + type2test = LinkedHashMap + +class JavaHashtableTest(JavaIntegrationTest): + type2test = Hashtable + +class JavaConcurrentHashMapTest(JavaIntegrationTest): + type2test = ConcurrentHashMap class JavaDictTest(test_dict.DictTest): + # Extend Python standard tests for dict. (Also used for Map proxies.) - _class = HashMap + type2test = dict def test_copy_java_hashtable(self): x = Hashtable() xc = x.copy() self.assertEqual(type(x), type(xc)) - def test_fromkeys(self): - super(JavaDictTest, self).test_fromkeys() - self.assertEqual(self._class.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) - def test_repr_value_None(self): - x = self._class({1:None}) + x = self.type2test({1:None}) self.assertEqual(repr(x), '{1: None}') def test_set_return_None(self): - x = self._class({1:2}) + x = self.type2test({1:2}) self.assertEqual(x.__setitem__(1, 3), None) self.assertEqual(x.__getitem__(1), 3) def test_del_return_None(self): - x = self._class({1:2}) + x = self.type2test({1:2}) self.assertEqual(x.__delitem__(1), None) self.assertEqual(len(x), 0) @@ -204,6 +287,34 @@ def assert_not_property(self, prop, a, b): with self.assertRaises(AssertionError): prop(self._make_dict(a), b) + def test_list_equality(self): + class A(dict): pass + d = {'a':1, u'\xe7':2, u'\U00010842':3, 42:None} + for dtype in (dict, self.type2test, A): + self.assertEquals([dtype()], [dict()]) + self.assertEquals([dtype(d)], [d]) + + # Some variants with unicode keys + + def test_repr_unicode(self): + d = self._make_dict({}) + d[u'3\uc6d4'] = 2 + self.assertEqual(repr(d), "{u'3\\uc6d4': 2}") + + d = self._make_dict({}) + d[2] = u'\u039c\u03ac\u03c1\u03c4\u03b9\u03bf\u03c2' + self.assertEqual(repr(d), "{2: u'\\u039c\\u03ac\\u03c1\\u03c4\\u03b9\\u03bf\\u03c2'}") + + d = self._make_dict({}) + d[u'\uc6d4'] = d + self.assertEqual(repr(d), "{u'\\uc6d4': {...}}") + + def test_fromkeys_unicode(self): + self.assertEqual(self.type2test.fromkeys(u'\U00010840\U00010841\U00010842', u'\u1810'), + {u'\U00010840':u'\u1810', u'\U00010841':u'\u1810', u'\U00010842':u'\u1810'}) + self.assertEqual(self.type2test.fromkeys(u'\U00010840\U00010841\U00010842'), + {u'\U00010840':None, u'\U00010841':None, u'\U00010842':None}) + # NOTE: when comparing dictionaries below exclusively in Java # space, keys like 1 and 1L are different objects. Only when they # are brought into Python space by Py.java2py, as is needed when @@ -243,20 +354,190 @@ def test_gt(self): self.assertGreater({1L: 2L, 3L: 4L}, self._make_dict({1: 2})) -class PyStringMapTest(test_dict.DictTest): +class NullAcceptingDictTest(JavaDictTest): + # Extension of Java Map proxy tests to cases where the underlying + # container is able to accept nulls. Same tests as for dict (mostly). + + def test_missing(self): + # Proxy map types are not expected to support __missing__. + self.assertFalse(hasattr(self.type2test, "__missing__")) + self.assertFalse(hasattr(self._make_dict({}), "__missing__")) + + def test_fromkeys(self): + # Adapted from test_dict.DictTest.test_fromkeys by removal of test + # sub-classes since this does not work with proxy types. + Dict = self.type2test + + self.assertEqual(Dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + + d = self._make_dict({}) + self.assertIsNot(d.fromkeys('abc'), d) + self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) + self.assertEqual(d.fromkeys([]), {}) + def g(): + yield 1 + self.assertEqual(d.fromkeys(g()), {1:None}) + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3) + + class Exc(Exception): pass + class BadSeq(object): + def __iter__(self): + return self + def next(self): + raise Exc() + self.assertRaises(Exc, Dict.fromkeys, BadSeq()) + +class NullRejectingDictTest(NullAcceptingDictTest): + # Adaptation of Java Map proxy tests to cases where the underlying + # container cannot accept nulls, therefore None cannot be stored. + + def test_reject_none(self): + d = self._make_dict({'a': 1}) + with self.assertRaises(ValueError): + d['a'] = None + with self.assertRaises(ValueError): + d['b'] = None + # There is no __init__ or __new__ we can customise, so raises NullPointerException. + # self.assertRaises(ValueError, self._make_dict, {'c': None}) + self.assertRaises(ValueError, d.update, {'c': None}) + with self.assertRaises(ValueError): + d.update(c=None) + self.assertRaises(ValueError, d.fromkeys, 'cde') + self.assertRaises(ValueError, d.fromkeys, 'cde', None) + + def test_list_equality(self): + class A(dict): pass + d = {'a':1, u'\xe7':2, u'\U00010842':3, 42:True} + for dtype in (dict, self.type2test, A): + self.assertEquals([dtype()], [dict()]) + self.assertEquals([dtype(d)], [d]) + + @unittest.skip("not relevant since cannot hold None.") + def test_repr_value_None(self): pass + + def test_fromkeys(self): + # Adapted from test_dict.DictTest.test_fromkeys avoiding None + # (except as test) and by removal of test sub-classing. + Dict = self.type2test + + self.assertEqual(Dict.fromkeys('abc', 42), {'a':42, 'b':42, 'c':42}) + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3, 42) + self.assertRaises(ValueError, self._make_dict({}).fromkeys, 'abc', None) + + d = self._make_dict({}) + self.assertIsNot(d.fromkeys('abc', 42), d) + self.assertEqual(d.fromkeys('abc', 42), {'a':42, 'b':42, 'c':42}) + self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) + self.assertEqual(d.fromkeys([], 42), {}) + def g(): + yield 1 + self.assertEqual(d.fromkeys(g(), 42), {1:42}) + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3) + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3, 42) + + class Exc(Exception): pass + class BadSeq(object): + def __iter__(self): + return self + def next(self): + raise Exc() + self.assertRaises(Exc, Dict.fromkeys, BadSeq()) + + def test_fromkeys_unicode(self): + self.assertEqual(self.type2test.fromkeys(u'\U00010840\U00010841\U00010842', u'\u1810'), + {u'\U00010840':u'\u1810', u'\U00010841':u'\u1810', u'\U00010842':u'\u1810'}) + + def test_setdefault(self): + # Adapted from test_dict.DictTest.test_setdefault avoiding None + d = self._make_dict({'key0': False}) + d.setdefault('key0', []) + self.assertIs(d.setdefault('key0'), False) + d.setdefault('key', []).append(3) + self.assertEqual(d['key'][0], 3) + d.setdefault('key', []).append(4) + self.assertEqual(len(d['key']), 2) + self.assertRaises(TypeError, d.setdefault) + + class Exc(Exception): pass + + class BadHash(object): + fail = False + def __hash__(self): + if self.fail: + raise Exc() + else: + return 42 + + x = BadHash() + d[x] = 42 + x.fail = True + self.assertRaises(Exc, d.setdefault, x, []) + + @unittest.skip("See bjo #2746. Java keys() returns an Enumerator.") + def test_has_key(self): pass # defining here only so we can skip it + + @unittest.skip("See bjo #2746. Java keys() returns an Enumerator.") + def test_keys(self): pass # defining here only so we can skip it + + +class PyStringMapDictTest(test_dict.DictTest): # __dict__ for objects uses PyStringMap for historical reasons, so # we have to test separately - def _class(self, d): - # PyStringMap pretends to be a regular dict, so doing - # type(C().__dict__)() will not be helpful - it creates a - # regular dict. So explicitly create new objects and return - # their __dict__ - class C(object): - pass - newdict = C().__dict__ - newdict.update(d) - return newdict + type2test = stringmap + + def test_missing(self): + Dict = self.type2test + # Make sure dict doesn't have a __missing__ method + self.assertFalse(hasattr(Dict, "__missing__")) + self.assertFalse(hasattr(self._make_dict({}), "__missing__")) + # PyStringMap is not expected to support __missing__ as it cannot be sub-classed. + # At least, it wasn't added when it was added to PyDictionary. + + def test_fromkeys(self): + # Based on test_dict.DictTest.test_fromkeys, without sub-classing stringmap + Dict = self.type2test + + self.assertEqual(Dict.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + + d = self._make_dict({}) + self.assertIsNot(d.fromkeys('abc'), d) + self.assertEqual(d.fromkeys('abc'), {'a':None, 'b':None, 'c':None}) + self.assertEqual(d.fromkeys((4,5),0), {4:0, 5:0}) + self.assertEqual(d.fromkeys([]), {}) + def g(): + yield 1 + self.assertEqual(d.fromkeys(g()), {1:None}) + self.assertRaises(TypeError, self._make_dict({}).fromkeys, 3) + + class Exc(Exception): pass + + class BadSeq(object): + def __iter__(self): + return self + def next(self): + raise Exc() + + self.assertRaises(Exc, Dict.fromkeys, BadSeq()) + + # test fast path for dictionary inputs + d = Dict(zip(range(6), range(6))) + self.assertEqual(Dict.fromkeys(d, 0), Dict(zip(range(6), [0]*6))) + + + +class JavaHashMapDictTest(NullAcceptingDictTest): + type2test = HashMap + +class JavaLinkedHashMapDictTest(NullAcceptingDictTest): + type2test = LinkedHashMap + +class JavaHashtableDictTest(NullRejectingDictTest): + type2test = Hashtable + +class JavaConcurrentHashMapDictTest(NullRejectingDictTest): + type2test = ConcurrentHashMap def test_main(): @@ -265,9 +546,18 @@ def test_main(): DictCmpTest, DictMiscTest, DerivedDictTest, - JavaIntegrationTest, + JavaHashMapTest, + JavaLinkedHashMapTest, + JavaConcurrentHashMapTest, + JavaHashtableTest, JavaDictTest, - PyStringMapTest) + PyStringMapDictTest, + JavaHashMapDictTest, + JavaLinkedHashMapDictTest, + JavaHashtableDictTest, + JavaConcurrentHashMapDictTest, + ) + if __name__ == '__main__': test_main() diff --git a/Lib/test/test_email.py b/Lib/test/test_email.py index d857e6ca5..c8c25b6af 100644 --- a/Lib/test/test_email.py +++ b/Lib/test/test_email.py @@ -3,14 +3,13 @@ # The specific tests now live in Lib/email/test from email.test.test_email import TestEncoders, suite +from email.test.test_email_renamed import suite as suite2 from test import test_support def test_main(): - #This one doesn't work on Jython - del TestEncoders.test_encode7or8bit - - s = suite() test_support.run_unittest(suite()) + test_support.run_unittest(suite2()) if __name__ == '__main__': test_main() + diff --git a/Lib/test/test_email_jy.py b/Lib/test/test_email_jy.py new file mode 100644 index 000000000..113b94ae6 --- /dev/null +++ b/Lib/test/test_email_jy.py @@ -0,0 +1,12 @@ +# Copyright (C) 2001,2002 Python Software Foundation +# Jython override to enforce C locale during locale beta +from test import test_email +from test import test_support + +def test_main(initialize=True): + test_support.force_reset_locale(initialize) + test_email.test_main() + +if __name__ == '__main__': + test_main(False) + diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py index a3b757fea..e28d78d66 100644 --- a/Lib/test/test_exceptions.py +++ b/Lib/test/test_exceptions.py @@ -524,7 +524,6 @@ def test_0_args(self): self.check_same_msg(Exception(), '') - @unittest.skipIf(is_jython, "FIXME: not working in Jython") def test_0_args_with_overridden___str__(self): """Check same msg for exceptions with 0 args and overridden __str__""" # str() and unicode() on an exception with overridden __str__ that @@ -550,7 +549,6 @@ def test_1_arg(self): self.assertRaises(UnicodeEncodeError, str, e) self.assertEqual(unicode(e), u'f\xf6\xf6') - @unittest.skipIf(is_jython, "FIXME: not working in Jython") def test_1_arg_with_overridden___str__(self): """Check same msg for exceptions with overridden __str__ and 1 arg""" # when __str__ is overridden and __unicode__ is not implemented @@ -575,7 +573,6 @@ def test_many_args(self): for args in argslist: self.check_same_msg(Exception(*args), repr(args)) - @unittest.skipIf(is_jython, "FIXME: not working in Jython") def test_many_args_with_overridden___str__(self): """Check same msg for exceptions with overridden __str__ and many args""" # if __str__ returns an ascii string / ascii unicode string diff --git a/Lib/test/test_exceptions_jy.py b/Lib/test/test_exceptions_jy.py index 351659933..9b1ef8de6 100644 --- a/Lib/test/test_exceptions_jy.py +++ b/Lib/test/test_exceptions_jy.py @@ -70,11 +70,12 @@ def test_unicode_args(self): # But the exception hook, via Py#displayException, does not fail when attempting to __str__ the exception args with test_support.captured_stderr() as s: sys.excepthook(RuntimeError, u"Drink \u2615", None) - self.assertEqual(s.getvalue(), "RuntimeError\n") + # At minimum, it tells us what kind of exception it was + self.assertEqual(s.getvalue()[:12], "RuntimeError") # It is fine with ascii values, of course with test_support.captured_stderr() as s: sys.excepthook(RuntimeError, u"Drink java", None) - self.assertEqual(s.getvalue(), "RuntimeError: Drink java\n") + self.assertEqual(s.getvalue(), "RuntimeError: Drink java\n") def test_main(): diff --git a/Lib/test/test_file_jy.py b/Lib/test/test_file_jy.py index b84fe65c6..72b7b89ef 100644 --- a/Lib/test/test_file_jy.py +++ b/Lib/test/test_file_jy.py @@ -45,18 +45,18 @@ def test_issue1825(self): @unittest.skipUnless(hasattr(os, 'chmod'), 'chmod() support required for this test') def test_issue2081(self): - f = open(test_support.TESTFN, 'wb') - f.close() + with open(test_support.TESTFN, 'wb'): + pass os.chmod(test_support.TESTFN, 200) # write-only - f = open(test_support.TESTFN, 'w') # should succeed, raised IOError (permission denied) prior to fix - f.close() + with open(test_support.TESTFN, 'w'): # should succeed, raised IOError (permission denied) prior to fix + pass # http://bugs.jython.org/issue2358 def test_read_empty_file(self): - f = open(test_support.TESTFN, 'w') - f.close() - f = open(test_support.TESTFN) - self.assertEqual(f.read(), '') + with open(test_support.TESTFN, 'w'): + pass + with open(test_support.TESTFN) as f: + self.assertEqual(f.read(), '') # http://bugs.jython.org/issue2358 @unittest.skipUnless(System.getProperty('os.name') == u'Linux', 'Linux required') diff --git a/Lib/test/test_format_jy.py b/Lib/test/test_format_jy.py index dc68443d0..049df6df2 100644 --- a/Lib/test/test_format_jy.py +++ b/Lib/test/test_format_jy.py @@ -22,6 +22,29 @@ def __init__(self, x): self.x = x def __float__(self): return self. x self.assertEqual('1.0', '%.1f' % Foo(1.0)) + def test_formatting_int_min_value_as_decimal(self): + # Test for http://bugs.jython.org/issue2672 + x = int(-(1<<31)) + self.assertEqual('-2147483648', '%d' % x) + self.assertEqual('-2147483648', '%i' % x) + + def test_formatting_int_min_value_as_hex(self): + # Test for http://bugs.jython.org/issue2672 + x = int(-(1<<31)) + self.assertEqual('-80000000', '%x' % x) + self.assertEqual('-80000000', '%X' % x) + + def test_formatting_int_min_value_as_octal(self): + # Test for http://bugs.jython.org/issue2672 + x = int(-(1<<31)) + self.assertEqual('-20000000000', '%o' % x) + + def test_formatting_int_min_value_as_binary(self): + # Test for http://bugs.jython.org/issue2672 + x = int(-(1<<31)) + self.assertEqual('-10000000000000000000000000000000', '{0:b}'.format(x)) + + class FormatUnicodeBase(unittest.TestCase): # Test padding non-BMP result @@ -29,6 +52,7 @@ def test_pad_string(self): self.padcheck(u"architect") self.padcheck(u'a\U00010001cde') + class FormatUnicodeClassic(FormatUnicodeBase): # Check using %-formatting @@ -39,6 +63,7 @@ def padcheck(self, s): self.assertEqual(u' '*6 + s[0:4], '%010.4s' % s) self.assertEqual(s[0:3] + u' '*5, '%-8.3s' % s) + class FormatUnicodeModern(FormatUnicodeBase): # Check using __format__ diff --git a/Lib/test/test_gc_jy.py b/Lib/test/test_gc_jy.py index 42fa5d47a..9159eb4e9 100644 --- a/Lib/test/test_gc_jy.py +++ b/Lib/test/test_gc_jy.py @@ -33,7 +33,7 @@ def setUpClass(cls): gc.stopMonitoring() except Exception: pass - + @classmethod def tearDownClass(cls): try: @@ -371,7 +371,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -385,7 +385,7 @@ def __del__(self): c = Test_Resurrection("c") c.a = a c.toResurrect = Test_Finalizable("d") - + del a del c self.assertNotEqual(gc.collect(), 0) @@ -552,7 +552,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -566,7 +566,7 @@ def __del__(self): c = Test_Resurrection("c") c.a = a c.toResurrect = Test_Finalizable("d") - + del a del c self.assertNotEqual(gc.collect(), 0) @@ -616,31 +616,31 @@ def tearDownClass(cls): def test_raw_forced_delayedFinalization(self): #print "test_raw_forced_delayedFinalization" comments = [] - + class Test_JavaAbortFinalizable(Object): def __init__(self, name, toAbort): self.name = name self.toAbort = toAbort - + def __repr__(self): return "<"+self.name+">" - + def finalize(self): gc.notifyPreFinalization() comments.append("del "+self.name) gc.abortDelayedFinalization(self.toAbort) gc.notifyPostFinalization() - + class Test_Finalizable(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" - + def __del__(self): comments.append("del "+self.name) - + def callback(obj): comments.append("callback0") @@ -666,12 +666,12 @@ def callback(obj): def test_raw_forced_delayedWeakrefCallback(self): comments = [] resurrected = [] - + class Test_JavaResurrectFinalizable(Object): def __init__(self, name, toResurrect): self.name = name self.toResurrect = toResurrect - + def __repr__(self): return "<"+self.name+">" @@ -684,20 +684,20 @@ def finalize(self): # We manually restore weak references: gc.restoreWeakReferences(self.toResurrect) gc.notifyPostFinalization() - + class Test_Finalizable(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" - + def __del__(self): comments.append("del "+self.name) - + def callback(obj): comments.append("callback") - + a = Test_Finalizable("a") b = Test_JavaResurrectFinalizable("b", a) wa = weakref.ref(a, callback) @@ -723,15 +723,15 @@ def callback(obj): def test_raw_forced_delayed(self): comments = [] - + class Test_JavaAbortFinalizable(Object): def __init__(self, name, toAbort): self.name = name self.toAbort = toAbort - + def __repr__(self): return "<"+self.name+">" - + def finalize(self): gc.notifyPreFinalization() comments.append("del "+self.name) @@ -826,7 +826,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -926,7 +926,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -976,7 +976,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -1035,7 +1035,7 @@ def __del__(self): class Test_Resurrection(object): def __init__(self, name): self.name = name - + def __repr__(self): return "<"+self.name+">" @@ -1071,11 +1071,10 @@ def __del__(self): self.assertEqual(wc(), None) -@unittest.skipUnless(test_support.is_jython, - ''' - The test involves Java-classes and is thus not supported by - non-Jython interpreters. - ''') +@unittest.skipUnless(test_support.is_jython and test_support.get_java_version() < (9,), + "Test is specific to Java versions <9") + # From Java 9 onwards we get ugly warnings. + # See discussion in http://bugs.jython.org/issue2656 class GCTests_Jy_TraverseByReflection(unittest.TestCase): @classmethod @@ -1083,6 +1082,7 @@ def setUpClass(cls): #Jython-specific block: try: cls.savedJythonGCFlags = gc.getJythonGCFlags() + gc.removeJythonGCFlags(gc.DONT_TRAVERSE_BY_REFLECTION) # i.e. enable ... gc.addJythonGCFlags(gc.SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING) gc.setMonitorGlobal(True) except Exception: @@ -1096,25 +1096,32 @@ def tearDownClass(cls): except Exception: pass - def test_TraverseByReflection(self): + def test_Field(self): gc.collect() - prt = GCTestHelper.reflectionTraverseTestField() del prt self.assertEqual(gc.collect(), 1) + def test_List(self): + gc.collect() prt = GCTestHelper.reflectionTraverseTestList() del prt self.assertEqual(gc.collect(), 1) + def test_Array(self): + gc.collect() prt = GCTestHelper.reflectionTraverseTestArray() del prt self.assertEqual(gc.collect(), 1) + def test_PyList(self): + gc.collect() prt = GCTestHelper.reflectionTraverseTestPyList() del prt self.assertEqual(gc.collect(), 2) + def test_Cycle(self): + gc.collect() prt = GCTestHelper.reflectionTraverseTestCycle() del prt self.assertEqual(gc.collect(), 0) diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py index f62a44b5b..b0bf2c50c 100644 --- a/Lib/test/test_genexps.py +++ b/Lib/test/test_genexps.py @@ -98,7 +98,7 @@ Verify that parenthesis are required when used as a keyword argument value >>> dict(a = (i for i in xrange(10))) #doctest: +ELLIPSIS - {'a': } + {'a': at ...>} Verify early binding for the outermost for-expression diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py index 0166dad26..8a2db9508 100644 --- a/Lib/test/test_httplib.py +++ b/Lib/test/test_httplib.py @@ -241,6 +241,120 @@ def test_malformed_headers_coped_with(self): self.assertEqual(resp.getheader('First'), 'val') self.assertEqual(resp.getheader('Second'), 'val') + def test_malformed_truncation(self): + # Other malformed header lines, especially without colons, used to + # cause the rest of the header section to be truncated + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'Public-Key-Pins: \n' + b'pin-sha256="xxx=";\n' + b'report-uri="https://..."\r\n' + b'Transfer-Encoding: chunked\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertIsNotNone(resp.getheader('Public-Key-Pins')) + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + def test_blank_line_forms(self): + # Test that both CRLF and LF blank lines can terminate the header + # section and start the body + for blank in (b'\r\n', b'\n'): + resp = b'HTTP/1.1 200 OK\r\n' b'Transfer-Encoding: chunked\r\n' + resp += blank + resp += b'4\r\nbody\r\n0\r\n\r\n' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + resp = b'HTTP/1.0 200 OK\r\n' + blank + b'body' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'body') + + # A blank line ending in CR is not treated as the end of the HTTP + # header section, therefore header fields following it should be + # parsed if possible + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'\r' + b'Name: value\r\n' + b'Transfer-Encoding: chunked\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + # No header fields nor blank line + resp = b'HTTP/1.0 200 OK\r\n' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'') + + def test_from_line(self): + # The parser handles "From" lines specially, so test this does not + # affect parsing the rest of the header section + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'From start\r\n' + b' continued\r\n' + b'Name: value\r\n' + b'From middle\r\n' + b' continued\r\n' + b'Transfer-Encoding: chunked\r\n' + b'From end\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertIsNotNone(resp.getheader('Name')) + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + resp = ( + b'HTTP/1.0 200 OK\r\n' + b'From alone\r\n' + b'\r\n' + b'body' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'body') + + def test_parse_all_octets(self): + # Ensure no valid header field octet breaks the parser + body = ( + b'HTTP/1.1 200 OK\r\n' + b"!#$%&'*+-.^_`|~: value\r\n" # Special token characters + b'VCHAR: ' + bytearray(range(0x21, 0x7E + 1)) + b'\r\n' + b'obs-text: ' + bytearray(range(0x80, 0xFF + 1)) + b'\r\n' + b'obs-fold: text\r\n' + b' folded with space\r\n' + b'\tfolded with tab\r\n' + b'Content-Length: 0\r\n' + b'\r\n' + ) + sock = FakeSocket(body) + resp = httplib.HTTPResponse(sock) + resp.begin() + self.assertEqual(resp.getheader('Content-Length'), '0') + self.assertEqual(resp.getheader("!#$%&'*+-.^_`|~"), 'value') + vchar = ''.join(map(chr, range(0x21, 0x7E + 1))) + self.assertEqual(resp.getheader('VCHAR'), vchar) + self.assertIsNotNone(resp.getheader('obs-text')) + folded = resp.getheader('obs-fold') + self.assertTrue(folded.startswith('text')) + self.assertIn(' folded with space', folded) + self.assertTrue(folded.endswith('folded with tab')) + def test_invalid_headers(self): conn = httplib.HTTPConnection('example.com') conn.sock = FakeSocket('') @@ -525,7 +639,7 @@ def test_filenoattr(self): self.assertTrue(hasattr(resp,'fileno'), 'HTTPResponse should expose a fileno attribute') - # Test lines overflowing the max line size (_MAXLINE in http.client) + # Test lines overflowing the max line size (_MAXLINE in httplib) def test_overflowing_status_line(self): self.skipTest("disabled for HTTP 0.9 support") @@ -624,7 +738,7 @@ def testHTTPConnectionSourceAddress(self): def testHTTPSConnectionSourceAddress(self): self.conn = httplib.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. diff --git a/Lib/test/test_httpservers.py b/Lib/test/test_httpservers.py index 80dbac861..9ee4bc1bc 100644 --- a/Lib/test/test_httpservers.py +++ b/Lib/test/test_httpservers.py @@ -378,6 +378,9 @@ def test_invalid_requests(self): @unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0, "This test can't be run reliably as root (issue #13308).") +@unittest.skipIf((not hasattr(os, 'symlink')) and + sys.executable.encode('ascii', 'replace') != sys.executable, + "Executable path is not pure ASCII.") # these fail for CPython too class CGIHTTPServerTestCase(BaseTestCase): class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler): pass @@ -414,10 +417,7 @@ def tearDown(self): os.chdir(self.cwd) if self.pythonexe != sys.executable: os.remove(self.pythonexe) - os.remove(self.file1_path) - os.remove(self.file2_path) - os.rmdir(self.cgi_dir) - os.rmdir(self.parent_dir) + test_support.rmtree(self.parent_dir) finally: BaseTestCase.tearDown(self) diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index dcbf6b7c1..97ec12d34 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -142,9 +142,9 @@ def test_rewrite_pyc_with_read_only_source(self): # Write a Python file, make it read-only and import it with open(fname, 'w') as f: f.write("x = 'original'\n") - # Tweak the mtime of the source to ensure pyc gets updated later + # Tweak the mtime of the source 10s later to ensure compiled looks out of date s = os.stat(fname) - os.utime(fname, (s.st_atime, s.st_mtime-100000000)) + os.utime(fname, (s.st_atime, s.st_mtime+10000)) os.chmod(fname, 0400) m1 = __import__(TESTFN) self.assertEqual(m1.x, 'original') @@ -653,8 +653,14 @@ def tearDown(self): sys.path[:] = self.orig_sys_path def test_main(verbose=None): - run_unittest(ImportTests, PycRewritingTests, PathsTests, - RelativeImportTests, TestSymbolicallyLinkedPackage) + run_unittest( + ImportTests, + PycRewritingTests, + PathsTests, + RelativeImportTests, + TestSymbolicallyLinkedPackage + ) + if __name__ == '__main__': # Test needs to be a package, so we can do relative imports. diff --git a/Lib/test/test_import_jy.py b/Lib/test/test_import_jy.py index 9d928d180..600ddf5d9 100644 --- a/Lib/test/test_import_jy.py +++ b/Lib/test/test_import_jy.py @@ -11,6 +11,7 @@ import tempfile import unittest import subprocess +import zipfile from test import test_support from test_chdir import read, safe_mktemp, COMPILED_SUFFIX @@ -219,19 +220,239 @@ def test_issue1952(self): class UnicodeNamesTestCase(unittest.TestCase): + def test_import_non_ascii_module(self): + module = "mødülé" + with self.assertRaises(ImportError) as cm: + __import__(module) + def test_import_unicode_module(self): + module = u"mødülé" with self.assertRaises(UnicodeEncodeError) as cm: - __import__("mødülé") + __import__(module) self.assertEqual(cm.exception.encoding, "ascii") - self.assertEqual(cm.exception.object, "mødülé") + self.assertEqual(cm.exception.object, module) self.assertEqual(cm.exception.reason, "ordinal not in range(128)") +class MixedImportTestCase(unittest.TestCase): + # + # This test case depends on material in a file structure unpacked + # from an associated ZIP archive. The test depends on Python source + # and Java class files. The archive also contains the Java source + # from which the class files may be regenerated if necessary. + # + # To regenerate the class files, explode the archive in a + # convenient spot on the file system and compile them with javac at + # the lowest supported code standard (currently Java 7), e.g. (posh) + # PS jython-trunk> cd mylib + # PS mylib> javac $(get-childitem -Recurse -Name -Include "*.java") + # or the equivalent Unix command using find. + + ZIP = test_support.findfile("test_import_jy.zip") + + @classmethod + def setUpClass(cls): + td = tempfile.mkdtemp() + cls.source = os.path.join(td, "test.py") + cls.setpath = "import sys; sys.modules[0] = r'" + td + "'" + zip = zipfile.ZipFile(cls.ZIP, 'r') + zip.extractall(td) + cls.tmpdir = td + + @classmethod + def tearDownClass(cls): + td = cls.tmpdir + if td and os.path.isdir(td): + test_support.rmtree(td) + + def make_prog(self, *script): + "Write a program to test.py" + with open(self.source, "wt") as f: + print >> f, MixedImportTestCase.setpath + for line in script: + print >> f, line + print >> f, "raise SystemExit" + + def run_prog(self): + # Feed lines to interpreter and capture output + process = subprocess.Popen([sys.executable, "-S", MixedImportTestCase.source], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, err = process.communicate() + retcode = process.poll() + if retcode: + raise subprocess.CalledProcessError(retcode, sys.executable, output=err) + return output + + def module_regex(self, module): + "Partial filename from module" + sep = "\\" + os.path.sep + return sep + module.replace('.', sep) + + def check_package(self, line, module): + target = "Executed: .*" + self.module_regex(module) + "\\" + os.path.sep \ + + r"__init__(\.py|\$py\.class|\.pyc)" + self.assertRegexpMatches(line, target) + + def check_module(self, line, module): + "Check output from loading a module" + target = "Executed: .*" + self.module_regex(module) + r"(\.py|\$py\.class|\.pyc)" + self.assertRegexpMatches(line, target) + + def test_import_to_program(self): + # A Python module in a Python program + self.make_prog("import a.b.c.m", "print repr(a.b.c.m)") + out = self.run_prog().splitlines() + self.check_package(out[0], "a") + self.check_package(out[1], "a.b") + self.check_package(out[2], "a.b.c") + self.check_module(out[3], "a.b.c.m") + self.assertRegexpMatches(out[4], r"\") + + def test_import_to_program_no_magic(self): + # A Python module in a Python program (issue 2654) + self.make_prog("import a.b, a.b.c", "print repr(a.b.m3)") + try: + out = self.run_prog() + self.fail("reference to a.b.m3 did not raise exception") + except subprocess.CalledProcessError as e: + self.assertRegexpMatches(e.output, r"AttributeError: .* has no attribute 'm3'") + + def test_import_relative_implicit(self): + # A Python module by implicit relative import (no dots) + self.make_prog("import a.b.m3") + out = self.run_prog().splitlines() + self.check_package(out[0], "a") + self.check_package(out[1], "a.b") + self.check_module(out[2], "a.b.m3") + self.check_package(out[3], "a.b.c") + self.check_module(out[4], "a.b.c.m") + self.assertRegexpMatches(out[5], r"\") + + def test_import_absolute_implicit(self): + # A built-in module by absolute import (but relative must be tried first) + self.make_prog("import a.b.m4") + out = self.run_prog().splitlines() + self.check_package(out[0], "a") + self.check_package(out[1], "a.b") + self.check_module(out[2], "a.b.m4") + self.assertRegexpMatches(out[3], r"\") + + def test_import_from_module(self): + # A Python module by from-import + self.make_prog("import a.b.m5") + out = self.run_prog().splitlines() + self.check_package(out[0], "a") + self.check_package(out[1], "a.b") + self.check_module(out[2], "a.b.m5") + self.check_package(out[3], "a.b.c") + self.check_module(out[4], "a.b.c.m") + self.assertRegexpMatches(out[5], r"\") + self.assertRegexpMatches(out[6], r"1 2") + + def test_import_from_relative_module(self): + # A Python module by relative from-import + self.make_prog("import a.b.m6") + out = self.run_prog().splitlines() + self.check_package(out[0], "a") + self.check_package(out[1], "a.b") + self.check_module(out[2], "a.b.m6") + self.check_package(out[3], "a.b.c") + self.check_module(out[4], "a.b.c.m") + self.assertRegexpMatches(out[5], r"\") + self.assertRegexpMatches(out[6], r"1 2") + + def check_java_package(self, line, module): + target = r"\" + self.assertRegexpMatches(line, target) + + def test_import_java_java(self): + # A Java class in a Java package by from-import + self.make_prog("from jpkg.j import K", "print repr(K)") + out = self.run_prog().splitlines() + self.assertRegexpMatches(out[0], r"\") + + def test_import_java_java_magic(self): + # A Java class in a Java package + # with implicit sub-module and class import + self.make_prog( + "import jpkg", + "print repr(jpkg)", + "print repr(jpkg.j)", + "print repr(jpkg.j.K)", + "print repr(jpkg.L)") + out = self.run_prog().splitlines() + self.check_java_package(out[0], "jpkg") + self.check_java_package(out[1], "jpkg.j") + self.assertRegexpMatches(out[2], r"\") + self.assertRegexpMatches(out[3], r"\") + + def test_import_java_python(self): + # A Java class in a Python package by from-import + self.make_prog("from mix.b import K1", "print repr(K1)") + out = self.run_prog().splitlines() + self.check_package(out[0], "mix") + self.check_package(out[1], "mix.b") + self.assertRegexpMatches(out[2], r"\") + + def test_import_java_python_magic(self): + # A Java class in a Python package + # with implicit sub-module and class import + self.make_prog( + "import mix", + "print repr(mix.b)", + "print repr(mix.b.K1)", + "import mix.b", + "print repr(mix.b)", + "print repr(mix.b.K1)", + "print repr(mix.J1)") + out = self.run_prog().splitlines() + self.check_package(out[0], "mix") + self.check_java_package(out[1], "mix.b") + self.assertRegexpMatches(out[2], r"\") + self.check_package(out[3], "mix.b") + self.assertRegexpMatches(out[4], r"\") + self.assertRegexpMatches(out[5], r"\") + self.assertRegexpMatches(out[6], r"\") + + def test_import_javapkg_python(self): + # A Java package in a Python package + self.make_prog("import mix.j", "print repr(mix.j)", "print repr(mix.j.K2)") + out = self.run_prog().splitlines() + self.check_package(out[0], "mix") + self.check_java_package(out[1], "mix.j") + self.assertRegexpMatches(out[2], r"\") + + def test_import_java_from_javapkg(self): + # A Java class in a Java package in a Python package + self.make_prog("from mix.j import K2", "print repr(K2)") + out = self.run_prog().splitlines() + self.check_package(out[0], "mix") + self.assertRegexpMatches(out[1], r"\") + + def test_import_javapkg_magic(self): + # A Java class in a Java package in a Python package + # with implicit sub-module and class import + self.make_prog( + "import mix", + "print repr(mix.J1)", + "print repr(mix.j)", + "print repr(mix.j.K2)", + ) + out = self.run_prog().splitlines() + self.check_package(out[0], "mix") + self.assertRegexpMatches(out[1], r"\") + self.check_java_package(out[2], "mix.j") + self.assertRegexpMatches(out[3], r"\") + + def test_main(): - test_support.run_unittest(MislabeledImportTestCase, - OverrideBuiltinsImportTestCase, - ImpTestCase, - UnicodeNamesTestCase) + test_support.run_unittest( + MislabeledImportTestCase, + OverrideBuiltinsImportTestCase, + ImpTestCase, + UnicodeNamesTestCase, + MixedImportTestCase + ) if __name__ == '__main__': test_main() diff --git a/Lib/test/test_import_jy.zip b/Lib/test/test_import_jy.zip new file mode 100644 index 000000000..b76f43207 Binary files /dev/null and b/Lib/test/test_import_jy.zip differ diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py index c03c64d0e..86fa59771 100644 --- a/Lib/test/test_io.py +++ b/Lib/test/test_io.py @@ -650,13 +650,6 @@ class PyIOTest(IOTest): "len(array.array) returns number of elements rather than bytelength" )(IOTest.test_array_writes) - # When Jython tries to use UnsupportedOperation as _pyio defines it, it runs - # into a problem with multiple inheritance and the slots array: issue 1996. - # Override the affected test version just so we can skip it visibly. - @unittest.skipIf(support.is_jython, "FIXME: Jython issue 1996") - def test_invalid_operations(self): - pass - # Jython does not use integer file descriptors but an object instead. # Unfortunately, _pyio.open checks that it is an int. # Override the affected test versions just so we can skip them visibly. @@ -1480,13 +1473,6 @@ class CBufferedRWPairTest(BufferedRWPairTest): class PyBufferedRWPairTest(BufferedRWPairTest): tp = pyio.BufferedRWPair - # When Jython tries to use UnsupportedOperation as _pyio defines it, it runs - # into a problem with multiple inheritance and the slots array: issue 1996. - # Override the affected test version just so we can skip it visibly. - @unittest.skipIf(support.is_jython, "FIXME: Jython issue 1996") - def test_detach(self): - pass - class BufferedRandomTest(BufferedReaderTest, BufferedWriterTest): read_mode = "rb+" @@ -2217,6 +2203,7 @@ def test_seeking(self): self.assertEqual(s, prefix.decode("ascii")) self.assertEqual(f.tell(), prefix_size) self.assertEqual(f.readline(), u_suffix) + f.close() def test_seeking_too(self): # Regression test for a specific bug @@ -2229,6 +2216,7 @@ def test_seeking_too(self): f._CHUNK_SIZE = 2 f.readline() f.tell() + f.close() def test_seek_and_tell(self): #Test seek/tell using the StatefulIncrementalDecoder. @@ -2452,6 +2440,7 @@ def test_errors_property(self): self.assertEqual(f.errors, "replace") @unittest.skipUnless(threading, 'Threading required for this test.') + @unittest.skipIf(support.is_jython, "Not thread-safe: Jython issue 2588.") def test_threads_write(self): # Issue6750: concurrent writes could duplicate data event = threading.Event() @@ -2906,13 +2895,6 @@ class CMiscIOTest(MiscIOTest): class PyMiscIOTest(MiscIOTest): io = pyio - # When Jython tries to use UnsupportedOperation as _pyio defines it, it runs - # into a problem with multiple inheritance and the slots array: issue 1996. - # Override the affected test version just so we can skip it visibly. - @unittest.skipIf(support.is_jython, "FIXME: Jython issue 1996") - def test_io_after_close(self): - pass - # Jython does not use integer file descriptors but an object instead. # Unfortunately, _pyio.open checks that it is an int. # Override the affected test version just so we can skip it visibly. diff --git a/Lib/test/test_isinstance.py b/Lib/test/test_isinstance.py index 9befca62d..83fcfdb61 100644 --- a/Lib/test/test_isinstance.py +++ b/Lib/test/test_isinstance.py @@ -246,11 +246,13 @@ def test_subclass_tuple(self): if test_support.have_unicode: self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring)))) + @unittest.skipIf(test_support.is_jython, "See http://bugs.jython.org/issue2536.") def test_subclass_recursion_limit(self): # make sure that issubclass raises RuntimeError before the C stack is # blown self.assertRaises(RuntimeError, blowstack, issubclass, str, str) + @unittest.skipIf(test_support.is_jython, "See http://bugs.jython.org/issue2536.") def test_isinstance_recursion_limit(self): # make sure that issubclass raises RuntimeError before the C stack is # blown diff --git a/Lib/test/test_java_integration.py b/Lib/test/test_java_integration.py index db484ff8f..b310fe715 100644 --- a/Lib/test/test_java_integration.py +++ b/Lib/test/test_java_integration.py @@ -13,6 +13,7 @@ from collections import deque from test import test_support +from distutils.spawn import find_executable from java.lang import ( ClassCastException, ExceptionInInitializerError, UnsupportedOperationException, @@ -44,6 +45,7 @@ from javatests.ProxyTests import NullToString, Person from clamp import SerializableProxies +from unittest.case import skip @@ -115,7 +117,7 @@ def test_inheriting_half_bean_issue1333(self): def test_awt_hack(self): # We ignore several deprecated methods in java.awt.* in favor of bean properties that were - # addded in Java 1.1. This tests that one of those bean properties is visible. + # added in Java 1.1. This tests that one of those bean properties is visible. c = Container() c.size = 400, 300 self.assertEquals(Dimension(400, 300), c.size) @@ -126,6 +128,7 @@ def setUp(self): def tearDown(self): sys.stdout = self.orig_stdout + test_support.unlink(test_support.TESTFN) def test_stdout_outputstream(self): out = FileOutputStream(test_support.TESTFN) @@ -233,6 +236,7 @@ class Keywords(object): Keywords.with = lambda self: "with" Keywords.yield = lambda self: "yield" + class PyReservedNamesTest(unittest.TestCase): "Access to reserved words" @@ -329,6 +333,7 @@ def test_with(self): def test_yield(self): self.assertEquals(self.kws.yield(), "yield") + class ImportTest(unittest.TestCase): def test_bad_input_exception(self): self.assertRaises(ValueError, __import__, '') @@ -377,6 +382,13 @@ def test_string_not_iterable(self): x = String('test') self.assertRaises(TypeError, list, x) + def test_null_tostring(self): + # http://bugs.jython.org/issue1819 + nts = NullToString() + self.assertEqual(repr(nts), '') + self.assertEqual(str(nts), '') + self.assertEqual(unicode(nts), '') + class JavaDelegationTest(unittest.TestCase): def test_list_delegation(self): for c in ArrayList, Vector: @@ -484,8 +496,11 @@ def test_nonexistent_import_with_security(self): # script must lie within python.home for this test to work return policy = test_support.findfile("python_home.policy") - self.assertEquals(subprocess.call([sys.executable, "-J-Dpython.cachedir.skip=true", - "-J-Djava.security.manager", "-J-Djava.security.policy=%s" % policy, script]), + self.assertEquals( + subprocess.call([sys.executable, + "-J-Dpython.cachedir.skip=true", + "-J-Djava.security.manager", + "-J-Djava.security.policy=%s" % policy, script]), 0) def test_import_signal_fails_with_import_error_using_security(self): @@ -527,6 +542,9 @@ def test_adding_attributes(self): self.assertEquals(7, m.initial) self.assertEquals(None, m.nonexistent, "Nonexistent fields should be passed on to the Map") + +class JavaMROTest(unittest.TestCase): + def test_adding_on_interface(self): GetitemAdder.addPredefined() class UsesInterfaceMethod(FirstPredefinedGetitem): @@ -539,26 +557,19 @@ def test_add_on_mro_conflict(self): self.assertRaises(TypeError, __import__, "org.python.tests.mro.ConfusedOnImport") self.assertRaises(TypeError, GetitemAdder.addPostdefined) - def test_null_tostring(self): - # http://bugs.jython.org/issue1819 - nts = NullToString() - self.assertEqual(repr(nts), '') - self.assertEqual(str(nts), '') - self.assertEqual(unicode(nts), '') - def test_diamond_inheritance_of_iterable_and_map(self): - """Test deeply nested diamond inheritance of Iterable and Map, as see in some Clojure classes""" - # http://bugs.jython.org/issue1878 - from javatests import DiamondIterableMapMRO # this will raise a TypeError re MRO conflict without the fix - # Verify the correct MRO is generated - order is of course *important*; - # the following used types are implemented as empty interfaces/abstract classes, but match the inheritance graph - # and naming of Clojure/Storm. - # - # Also instead of directly importing, which would cause annoying bloat in javatests by making lots of little files, - # just match using str - this will still be stable/robust. - self.assertEqual( - str(DiamondIterableMapMRO.__mro__), - "(, , , , , , , , , , , , , , )") + """Test deeply nested diamond inheritance of Iterable and Map""" + # http://bugs.jython.org/issue1878. Previously raised a TypeError (MRO conflict). + from javatests import DiamondIterableMapMRO + # The MRO places Iterable ahead of Map (so that __iter__ means j.u.Iterator.__iter__). + # The following used types are empty interfaces and abstract classes matching the + # inheritance graph and naming of Clojure/Storm, where the bug was discovered. + # Match using str - this will still be stable/robust. + mrostr = str(DiamondIterableMapMRO.__mro__) + jli = mrostr.find("java.lang.Iterable") + self.assertGreater(jli, -1, "Iterable must be in the MRO") + jum = mrostr.find("java.util.Map") + self.assertGreater(jum, jli, "Map must come later than Iterable") # And usable with __iter__ and map functionality m = DiamondIterableMapMRO() m["abc"] = 42 @@ -566,6 +577,16 @@ def test_diamond_inheritance_of_iterable_and_map(self): self.assertEqual(set(m), set(["abc", "xyz"])) self.assertEqual(m["abc"], 42) + def test_mro_eclipse(self): + # http://bugs.jython.org/issue2445 + from org.python.tests.mro import EclipseChallengeMRO + + def test_mro_ibmmq(self): + # http://bugs.jython.org/issue2445 + from org.python.tests.mro import IBMMQChallengeMRO + t = IBMMQChallengeMRO.mq.jms.MQQueue + + def roundtrip_serialization(obj): """Returns a deep copy of an object, via serializing it @@ -605,11 +626,13 @@ def resolveProxyClass(self, interfaceNames): def find_jython_jars(): # Uses the same classpath resolution as bin/jython - jython_jar_path = os.path.normpath(os.path.join(sys.executable, "../../jython.jar")) - jython_jar_dev_path = os.path.normpath(os.path.join(sys.executable, "../../jython-dev.jar")) + jython_bin = os.path.normpath(os.path.dirname(sys.executable)) + jython_top = os.path.dirname(jython_bin) + jython_jar_path = os.path.join(jython_top, 'jython.jar') + jython_jar_dev_path = os.path.join(jython_top, 'jython-dev.jar') if os.path.exists(jython_jar_dev_path): jars = [jython_jar_dev_path] - jars.extend(glob.glob(os.path.normpath(os.path.join(jython_jar_dev_path, "../javalib/*.jar")))) + jars.extend(glob.glob(os.path.join(jython_top, 'javalib', '*.jar'))) elif os.path.exists(jython_jar_path): jars = [jython_jar_path] else: @@ -617,8 +640,6 @@ def find_jython_jars(): return jars - - class JavaSource(SimpleJavaFileObject): def __init__(self, name, source): @@ -636,6 +657,8 @@ def getCharContent(self, ignore): return self._source +@unittest.skipIf(ToolProvider.getSystemJavaCompiler() is None, + "No Java compiler available. Is JAVA_HOME pointing to a JDK?") def compile_java_source(options, class_name, source): """Compiles a single java source "file" contained in the string source @@ -686,9 +709,13 @@ def test_builtin_names(self): names = [x for x in dir(__builtin__)] self.assertEqual(names, roundtrip_serialization(names)) + @unittest.skipUnless(find_executable('jar'), 'Need the jar command to run') def test_proxy_serialization(self): - """Proxies can be deserializable in a fresh JVM, including being able to "findPython" to get a PySystemState""" - tempdir = tempfile.mkdtemp() + # Proxies can be deserializable in a fresh JVM, including being able + # to "findPython" to get a PySystemState. + # tempdir gets combined with unicode paths derived from class names, + # so make it a unicode object. + tempdir = tempfile.mkdtemp().decode(sys.getfilesystemencoding()) old_proxy_debug_dir = org.python.core.Options.proxyDebugDirectory try: # Generate a proxy for Cat class; @@ -699,7 +726,8 @@ def test_proxy_serialization(self): # Create a jar file containing the Cat proxy; could use Java to do this; do it the easy way for now proxies_jar_path = os.path.join(tempdir, "proxies.jar") - subprocess.check_call(["jar", "cf", proxies_jar_path, "-C", tempdir, "org/"]) + subprocess.check_call(["jar", "cf", proxies_jar_path, "-C", tempdir, + "org" + os.path.sep]) # Serialize our cat output = ByteArrayOutputStream() @@ -717,19 +745,22 @@ def test_proxy_serialization(self): jars = find_jython_jars() jars.append(proxies_jar_path) classpath = os.pathsep.join(jars) - env = dict(os.environ) - env.update(JYTHONPATH=os.path.normpath(os.path.join(__file__, ".."))) - cmd = [os.path.join(System.getProperty("java.home"), "bin/java"), - "-classpath", classpath, "ProxyDeserialization", cat_path] - self.assertEqual(subprocess.check_output(cmd, env=env, universal_newlines=True), - "meow\n") + cmd = [os.path.join(System.getProperty("java.home"), "bin", "java"), + "-Dpython.path=" + os.path.dirname(__file__), + "-classpath", classpath, + "javatests.ProxyDeserialization", + cat_path] + self.assertEqual(subprocess.check_output(cmd, universal_newlines=True), "meow\n") finally: org.python.core.Options.proxyDebugDirectory = old_proxy_debug_dir shutil.rmtree(tempdir) + @unittest.skipUnless(find_executable('jar'), 'Need the jar command to run') def test_custom_proxymaker(self): - """Verify custom proxymaker supports direct usage of Python code in Java""" - tempdir = tempfile.mkdtemp() + # Verify custom proxymaker supports direct usage of Python code in Java + # tempdir gets combined with unicode paths derived from class names, + # so make it a unicode object. + tempdir = tempfile.mkdtemp().decode(sys.getfilesystemencoding()) try: SerializableProxies.serialized_path = tempdir import bark @@ -740,7 +771,8 @@ def test_custom_proxymaker(self): # Create a jar file containing the org.python.test.Dog proxy proxies_jar_path = os.path.join(tempdir, "proxies.jar") - subprocess.check_call(["jar", "cf", proxies_jar_path, "-C", tempdir, "org/"]) + subprocess.check_call(["jar", "cf", proxies_jar_path, "-C", tempdir, + "org" + os.path.sep]) # Build a Java class importing Dog source = """ @@ -774,12 +806,11 @@ def test_custom_proxymaker(self): # PySystemState (and Jython runtime) is initialized for # the proxy classpath += os.pathsep + tempdir - cmd = [os.path.join(System.getProperty("java.home"), "bin/java"), + cmd = [os.path.join(System.getProperty("java.home"), "bin", "java"), + "-Dpython.path=" + os.path.dirname(__file__), "-classpath", classpath, "BarkTheDog"] - env = dict(os.environ) - env.update(JYTHONPATH=os.path.normpath(os.path.join(__file__, ".."))) self.assertRegexpMatches( - subprocess.check_output(cmd, env=env, universal_newlines=True, + subprocess.check_output(cmd, universal_newlines=True, stderr=subprocess.STDOUT), r"^Class defined on CLASSPATH \n" "Rover barks 42 times$") @@ -828,7 +859,7 @@ def test_immutable(self): abc = String("abc") abc_copy = copy.copy(abc) self.assertEqual(id(abc), id(abc_copy)) - + fruits = ArrayList([String("apple"), String("banana")]) fruits_copy = copy.copy(fruits) self.assertEqual(fruits, fruits_copy) @@ -932,6 +963,7 @@ def test_main(): JavaDelegationTest, JavaReservedNamesTest, JavaStringTest, + JavaMROTest, JavaWrapperCustomizationTest, PyReservedNamesTest, SecurityManagerTest, @@ -939,7 +971,8 @@ def test_main(): SysIntegrationTest, TreePathTest, UnicodeTest, - SingleMethodInterfaceTest) + SingleMethodInterfaceTest, + ) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_java_visibility.py b/Lib/test/test_java_visibility.py index ff65befb2..9db85274f 100644 --- a/Lib/test/test_java_visibility.py +++ b/Lib/test/test_java_visibility.py @@ -1,4 +1,5 @@ import array +import os import unittest import subprocess import sys @@ -13,6 +14,7 @@ from org.python.tests.multihidden import BaseConnection class VisibilityTest(unittest.TestCase): + def test_invisible(self): for item in dir(Invisible): self.assert_(not item.startswith("package")) @@ -178,6 +180,7 @@ def test_extending_multiple_hidden_classes(self): class JavaClassTest(unittest.TestCase): + def test_class_methods_visible(self): self.assertFalse(HashMap.isInterface(), 'java.lang.Class methods should be visible on Class instances') @@ -198,6 +201,7 @@ def test_python_methods(self): self.assertEquals(3, s.b, "Defined fields should take precedence") class CoercionTest(unittest.TestCase): + def test_int_coercion(self): c = Coercions() self.assertEquals("5", c.takeInt(5)) @@ -234,12 +238,41 @@ def test_class_coercion(self): self.assertEquals(c.tellClassNameObject(ht), "class java.util.Hashtable") class RespectJavaAccessibilityTest(unittest.TestCase): + + def setUp(self): + self.command = [sys.executable] + + # NOTE: from Java 9 onwards, the JVM will complain about (but by default still allow) + # reflective access that does not respect Java accessibility rules. In order to avoid: + # WARNING: Illegal reflective access by org.python.core.PyJavaType ... + # and a threat that "illegal access operations will be denied in a future release", + # we add --add-opens specifications for all the packages needed in this test. + + def add_opens(self, module, package): + self.command.append("-J--add-opens") + self.command.append("-J{}/{}=ALL-UNNAMED".format(module, package)) + def run_accessibility_script(self, script, error=AttributeError): fn = test_support.findfile(script) + # Check expected error in current environment self.assertRaises(error, execfile, fn) - self.assertEquals(subprocess.call([sys.executable, "-J-Dpython.cachedir.skip=true", - "-J-Dpython.security.respectJavaAccessibility=false", fn]), - 0) + + # Prepare to break the rules + self.command.append("-J-Dpython.cachedir.skip=true") + self.command.append("-J-Dpython.security.respectJavaAccessibility=false") + if test_support.get_java_version() >= (9,): + # See all the cases for which we have forgotten --add-opens + self.command.append("-J--illegal-access=warn") + # Open the packages used in the scripts + self.add_opens("java.desktop", "java.awt.geom") + for package in ("lang", "util", "nio", "nio.charset"): + self.add_opens("java.base", "java." + package) + if test_support.get_java_version() >= (12,): + self.add_opens("java.base", "java.lang.constant") + + self.command.append(fn) + self.assertEquals(subprocess.call(self.command), 0) + def test_method_access(self): self.run_accessibility_script("call_protected_method.py") @@ -254,8 +287,11 @@ def test_overriding(self): self.run_accessibility_script("call_overridden_method.py") class ClassloaderTest(unittest.TestCase): + def test_loading_classes_without_import(self): - cl = test_support.make_jar_classloader("../callbacker_test.jar") + # Look for the Callbacker class ONLY in the special JAR + jar = os.path.join(sys.prefix, "callbacker_test.jar") + cl = test_support.make_jar_classloader(jar, None) X = cl.loadClass("org.python.tests.Callbacker") called = [] class Blah(X.Callback): @@ -265,11 +301,13 @@ def call(self, arg=None): self.assertEquals(None, called[0]) def test_main(): - test_support.run_unittest(VisibilityTest, + test_support.run_unittest( + VisibilityTest, JavaClassTest, CoercionTest, RespectJavaAccessibilityTest, - ClassloaderTest) + ClassloaderTest + ) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_joverload.py b/Lib/test/test_joverload.py index 98b963767..6aa86766d 100644 --- a/Lib/test/test_joverload.py +++ b/Lib/test/test_joverload.py @@ -138,6 +138,20 @@ def test_strings(self): "String...:[abc]") self.assertEqual(t.test([]), "String...:[]") + + self.assertEqual(t.testOneFixedArg("abc"), + "String arg1:abc String...:[]"); + self.assertEqual(t.testOneFixedArg("abc", "xyz"), + "String arg1:abc String...:[xyz]"); + self.assertEqual(t.testOneFixedArg("abc", "xyz", "123"), + "String arg1:abc String...:[xyz, 123]"); + + self.assertEqual(t.testTwoFixedArg("fix1", "fix2"), + "String arg1:fix1 String arg2:fix2 String...:[]"); + self.assertEqual(t.testTwoFixedArg("fix1", "fix2", "var1"), + "String arg1:fix1 String arg2:fix2 String...:[var1]"); + self.assertEqual(t.testTwoFixedArg("fix1", "fix2", "var1", "var2"), + "String arg1:fix1 String arg2:fix2 String...:[var1, var2]"); def test_lists(self): @@ -155,6 +169,31 @@ def test_lists(self): "List...:[[1, 2, 3]]") self.assertEqual(t.test([]), "List...:[]") + + def test_booleans(self): + t = Reflection.BooleanVarargs() + + + self.assertEqual(t.test(True, False), + "booleans...:[true, false]") + self.assertEqual(t.test(True), + "booleans...:[true]") + self.assertEqual(t.test(), + "booleans...:[]") + + self.assertEqual(t.testOneFixedArg(True), + "boolean arg1:true booleans...:[]"); + self.assertEqual(t.testOneFixedArg(True, False), + "boolean arg1:true booleans...:[false]"); + self.assertEqual(t.testOneFixedArg(True, False, True), + "boolean arg1:true booleans...:[false, true]"); + + self.assertEqual(t.testTwoFixedArg(True, False), + "boolean arg1:true boolean arg2:false booleans...:[]"); + self.assertEqual(t.testTwoFixedArg(True, False, True), + "boolean arg1:true boolean arg2:false booleans...:[true]"); + self.assertEqual(t.testTwoFixedArg(True, False, True, False), + "boolean arg1:true boolean arg2:false booleans...:[true, false]"); class ComplexOverloadingTests(unittest.TestCase): diff --git a/Lib/test/test_jser.py b/Lib/test/test_jser.py index 9d975a0d0..95a1b9562 100644 --- a/Lib/test/test_jser.py +++ b/Lib/test/test_jser.py @@ -15,7 +15,9 @@ def bar(self): class JavaSerializationTests(unittest.TestCase): def setUp(self): - self.sername = os.path.join(sys.prefix, "test.ser") + name = os.path.join(sys.prefix, "test.ser") + # As we are using java.io directly, ensure file name is a unicode + self.sername = name.decode(sys.getfilesystemencoding()) def tearDown(self): os.remove(self.sername) diff --git a/Lib/test/test_jy_internals.py b/Lib/test/test_jy_internals.py index 596775b5f..20a2534aa 100644 --- a/Lib/test/test_jy_internals.py +++ b/Lib/test/test_jy_internals.py @@ -2,33 +2,24 @@ test some jython internals """ import unittest -import time from test import test_support +import datetime import java import jarray +import os +import sys +import time +import weakref from org.python.core import Py from org.python.util import PythonInterpreter from javatests.TestSupport import invokePyTypeMethod from java.sql import Date, Time, Timestamp -import datetime - - -class MemoryLeakTests(unittest.TestCase): - - def test_class_to_test_weakness(self): - # regrtest for bug 1522, adapted from test code submitted by Matt Brinkley - # work around the fact that we can't look at PyType directly - # by using this helper function that reflects on PyType (and - # demonstrates here that it's the same as the builtin function - # `type`!) - class_to_type_map = invokePyTypeMethod(type, 'getClassToType') - def create_proxies(): - pi = PythonInterpreter() - pi.exec(""" +# Script for MemoryLeakTests.test_class_to_test_weakness +DOG = """ from java.lang import Comparable class Dog(Comparable): @@ -37,22 +28,83 @@ def compareTo(self, o): def bark(self): return 'woof woof' -Dog().bark() -""") - # get to steady state first, then verify we don't create new proxies - for i in xrange(2): - create_proxies() - # Ensure the reaper thread can run and clear out weak refs, so - # use this supporting function +dog = Dog() +dog.bark() +breed = dog.getClass() +""" + +def run_script(script, names): + """Run the script and return a weak list of the values named""" + pi = PythonInterpreter() + pi.exec(script) + if isinstance(names, str): + names = (names, ) + result = [] + for n in names: + obj = pi.getLocals()[n] + result.append(weakref.ref(obj)) + return result + +def survivors(weak_list): + """Set of all objects on the weak list that are still live.""" + s = {ref() for ref in weak_list} + s.discard(None) + return s + + +class MemoryLeakTests(unittest.TestCase): + + def test_class_to_test_weakness(self): + # regrtest for bug 1522, adapted from test code submitted by Matt Brinkley + + # We wish to demonstrate that the proxy created by a Python class and + # its PyType are GC'd when no longer in use, and therefore that the + # Jython type system does not keep a PyType alive gratuitously. We do + # this by holding weak references, then checking they're dead. + + # Get to steady state by creating >1 Dog and then GC-ing homeless ones. + battersea = [] + for i in range(2): + battersea.extend(run_script(DOG, ('Dog', 'dog', 'breed'))) + test_support.gc_collect() + + # This is the steady-state, GC number of Dog objects alive after GC: + start_size = len(survivors(battersea)) # probably = 1 + + # Add more Dogs and GC the homeless ones again. + for i in range(5): + battersea.extend(run_script(DOG, ('Dog', 'dog', 'breed'))) test_support.gc_collect() - # Given that taking the len (or size()) of Guava weak maps is - # eventually consistent, we should instead take a len of its - # keys. - start_size = len(list(class_to_type_map)) - for i in xrange(5): - create_proxies() + #print "\nDogs home =", battersea + #print "\nDogs alive =", survivors(battersea) + + # Post-GC number of Dogs should be as before + self.assertEqual(start_size, len(survivors(battersea))) + + def test_loading_classes_weakness(self): + # Show that classes loaded via a class loader are collectible once the + # class loader is not strongly reachable. + + # Reference all species of object on a weak list: + zoo = [] + + def activity(): + # Look for the Callbacker class ONLY in the special JAR + jar = os.path.join(sys.prefix, "callbacker_test.jar") + cldr = test_support.make_jar_classloader(jar, None) + CB = cldr.loadClass("org.python.tests.Callbacker") + cb = CB() + # Save locals as weak references (that we hope will go dead) + for obj in (cb, type(cb), cldr): + zoo.append(weakref.ref(obj)) + + # Load and use a class: objects created in zoo. + activity() + + #print "\nzoo =", zoo test_support.gc_collect() - self.assertEqual(start_size, len(list(class_to_type_map))) + #print "\nsurvivors =", survivors(zoo) + self.assertEqual(0, len(survivors(zoo))) class WeakIdentityMapTests(unittest.TestCase): @@ -93,6 +145,7 @@ def test_functionality(self): assert widmap.get(i) == 'i' # triggers stale weak refs cleanup assert widmap._internal_map_size() == 1 + class LongAsScaledDoubleValueTests(unittest.TestCase): def setUp(self): @@ -143,6 +196,7 @@ def test_no_worse_than_doubleValue(self): assert float((v+d)*256+y) == sdv(((v+d)*256+y)*256, e) assert e[0] == 1 + class ExtraMathTests(unittest.TestCase): def test_epsilon(self): from org.python.core.util import ExtraMath @@ -162,6 +216,7 @@ def test_closeFloor(self): ExtraMath.closeFloor(3.0 - 3.0 * ExtraMath.CLOSE), 2.0) self.assertEquals(ExtraMath.closeFloor(math.log10(10**3)), 3.0) + class DatetimeTypeMappingTest(unittest.TestCase): def test_date(self): self.assertEquals(datetime.date(2008, 5, 29), @@ -183,6 +238,7 @@ def test_datetime(self): self.assertEquals(datetime.datetime(2008, 5, 29, 16, 50, 1, 1), Py.newDatetime(Timestamp(108, 4, 29, 16, 50, 1, 1000))) + class IdTest(unittest.TestCase): def test_unique_ids(self): d = {} @@ -197,6 +253,7 @@ def test_unique_ids(self): self.assertEquals(cnt, 0) + class FrameTest(unittest.TestCase): def test_stack_frame_locals(self): def h(): @@ -268,6 +325,7 @@ def baz(self): foo() Bar().baz() + class ModuleTest(unittest.TestCase): def test_create_module(self): from org.python.core import PyModule, PyInstance @@ -279,6 +337,7 @@ def test_create_module(self): exec "b = 3" in test.__dict__ self.assertEquals(len(test.__dict__), 5) + def test_main(): test_support.run_unittest(__name__) diff --git a/Lib/test/test_jython_initializer.py b/Lib/test/test_jython_initializer.py index 83151587c..97f739e58 100644 --- a/Lib/test/test_jython_initializer.py +++ b/Lib/test/test_jython_initializer.py @@ -10,7 +10,9 @@ class TestUsingInitializer(unittest.TestCase): def test_syspath_initializer(self): fn = test_support.findfile('check_for_initializer_in_syspath.py') - env = dict(CLASSPATH='tests/data/initializer', + jar = test_support.findfile('syspath_initializer.jar') + env = dict(CLASSPATH=jar, + JAVA_HOME=sys.registry['java.home'], PATH=os.environ.get('PATH', '')) if WINDOWS: diff --git a/Lib/test/test_jython_launcher.py b/Lib/test/test_jython_launcher.py index 784e30121..edd868f32 100644 --- a/Lib/test/test_jython_launcher.py +++ b/Lib/test/test_jython_launcher.py @@ -31,7 +31,6 @@ def get_launcher(executable): # by the installer return executable - def get_uname(): _uname = None try: @@ -49,9 +48,8 @@ def classpath_delimiter(): class TestLauncher(unittest.TestCase): - - def get_cmdline(self, cmd, env): + def get_cmdline(self, cmd, env): output = subprocess.check_output(cmd, env=env).rstrip() if is_windows: return subprocess._cmdline2list(output) @@ -76,7 +74,7 @@ def get_properties(self, args): k, v = arg[2:].split("=") props[k] = v return props - + def test_classpath_env(self): env = self.get_newenv() env["CLASSPATH"] = some_jar @@ -105,7 +103,7 @@ def test_java_home(self): args = self.get_cmdline([launcher, "--print"], env) self.assertEqual(args[0], os.path.join(my_java, "bin", "java")) self.assertEqual(args[1], "-Xmx512m") - self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[2], "-Xss2560k") self.assertEqual(args[-1], "org.python.util.jython") def test_java_opts(self): @@ -115,7 +113,7 @@ def test_java_opts(self): props = self.get_properties(args) self.assertEqual(args[0], "java") self.assertEqual(args[1], "-Xmx2g") - self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[2], "-Xss2560k") self.assertEqual(args[3], "-classpath", args) self.assertEqual(args[4].split(classpath_delimiter())[-1], some_jar) self.assertEqual(args[-1], "org.python.util.jython") @@ -128,7 +126,7 @@ def test_default_options(self): props = self.get_properties(args) self.assertEqual(args[0], "java") self.assertEqual(args[1], "-Xmx512m") - self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[2], "-Xss2560k") self.assertEqual(args[-1], "org.python.util.jython") self.assertIn("python.home", props) self.assertIn("python.executable", props) @@ -159,7 +157,7 @@ def test_jython_opts_env(self): args = self.get_cmdline([launcher, "--print"], env) self.assertEqual(args[0], "java") self.assertEqual(args[1], "-Xmx512m") - self.assertEqual(args[2], "-Xss1024k") + self.assertEqual(args[2], "-Xss2560k") self.assertEqual(args[-3], "org.python.util.jython") self.assertEqual(args[-2], "-c") self.assertEqual(args[-1], "print 47") @@ -207,7 +205,7 @@ def assertCommand(self, command): def test_file(self): self.assertCommand(['test.py']) - + def test_dash(self): self.assertCommand(['-i']) diff --git a/Lib/test/test_large_method_bytecode_jy.py b/Lib/test/test_large_method_bytecode_jy.py new file mode 100644 index 000000000..90281ce00 --- /dev/null +++ b/Lib/test/test_large_method_bytecode_jy.py @@ -0,0 +1,92 @@ +""" +Tests Jython's capability to handle Python-functions and +methods that are so long that their JVM-bytecode exceeds +JVM method size restrictions. +The case that the main module code exceeds maximal length +is somewhat special, so it is explicitly tested. + +Note: As of this writing, a CPython 2.7 bytecode-file (.pyc) + is required for each module that contains an oversized + function. The pyc-file is only required at compile-time + in the sense that if you pre-compile py-files to classes, + you won't need to distribute the pyc-file; it gets + embedded into the class-file. +""" + +import unittest +from test import test_support + +class large_method_tests(unittest.TestCase): + '''Tests some oversized functions and methods. + ''' + + @classmethod + def setUpClass(cls): + import large_methods as _large_methods + global large_methods + large_methods = _large_methods + + def test_large_func(self): + '''Tests a function that slightly exceeds maximal JMV method + length. It is internally represented as CPython bytecode. + ''' + self.assertEqual(large_methods.large_function(), 'large 2300') + + def test_large_method(self): + '''Tests a method that slightly exceeds maximal JMV method + length. It is internally represented as CPython bytecode. + ''' + cl = large_methods.OversizedMethodHolder() + self.assertEqual(cl.large_function(), 'large_method 2300') + + def test_very_large_func(self): + '''Here we test a function that is so large that its Python bytecode + exceeds maximal String-literal length. It is automatically split up + into several literals. + ''' + self.assertEqual(large_methods.very_large_function(), 'very large 58900') + + def test_small_func(self): + '''We assert that ordinary-sized, i.e. JVM-bytecode methods still work + in context of PyBytecode. + ''' + self.assertEqual(large_methods.small_function(), 'small 10') + +class large_module_tests(unittest.TestCase): + '''Tests a module with oversized main-code. + So the whole module is represented as a single PyBytecode object. + Additionally same tests as in large_method_tests are applied. + ''' + + @classmethod + def setUpClass(cls): + import large_module as _large_module + global large_module + large_module = _large_module + + def test_large_module_main(self): + '''Tests the module's oversized main-code. + ''' + self.assertEqual(large_module.count, 2310) + + def test_large_module_method(self): + cl2 = large_module.OversizedMethodHolder() + self.assertEqual(cl2.large_function(), 'large_method 2300') + + def test_large_module_large_func(self): + self.assertEqual(large_module.large_function(), 'large 2300') + + def test_large_module_very_large_func(self): + self.assertEqual(large_module.very_large_function(), 'very large 58900') + + def test_large_module_small_func(self): + self.assertEqual(large_module.small_function(), 'small 10') + +def test_main(): + test_support.run_unittest( + large_method_tests, + large_module_tests + ) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_list_jy.py b/Lib/test/test_list_jy.py index 3cb54a242..fdda718d6 100644 --- a/Lib/test/test_list_jy.py +++ b/Lib/test/test_list_jy.py @@ -6,9 +6,10 @@ import test_list if test_support.is_jython: - from java.util import ArrayList + from java.util import ArrayList, LinkedList, Vector from java.lang import Integer, String + class ListTestCase(unittest.TestCase): def test_recursive_list_slices(self): @@ -60,6 +61,7 @@ def test_big_list(self): self.assertEqual(len(lst), 64000) self.assertEqual(sum(lst), 2047968000) + class ThreadSafetyTestCase(unittest.TestCase): def run_threads(self, f, num=10): @@ -112,6 +114,7 @@ def tester(): self.assert_(lst[1] in (1,10)) self.run_threads(tester) + class ExtendedSliceTestCase(unittest.TestCase): '''Really thrash extended slice operations on list.''' type2test = list @@ -228,17 +231,17 @@ def test_init(self): self.assertEqual(a, b) def test_extend_java_ArrayList(self): - jl = ArrayList([]) + jl = self.type2test([]) jl.extend([1,2]) - self.assertEqual(jl, ArrayList([1,2])) - jl.extend(ArrayList([3,4])) + self.assertEqual(jl, self.type2test([1,2])) + jl.extend(self.type2test([3,4])) self.assertEqual(jl, [1,2,3,4]) - + def test_remove(self): # Verifies that overloaded java.util.List#remove(int) method can still be used, but with Python index semantics # http://bugs.jython.org/issue2456 - jl = ArrayList(xrange(10, -1, -1)) # 10 .. 0, inclusive - jl.remove(0) # removes jl[-1] (=0) + jl = self.type2test(xrange(10, -1, -1)) # 10 .. 0, inclusive + jl.remove(0) # removes jl[-1] (=0) self.assertEqual(jl, range(10, 0, -1)) # 10 .. 1 self.assertRaises(ValueError, jl.remove, Integer(0)) # j.l.Integer does not support __index__ - maybe it should! jl.remove(0) # removes jl[0] (=10) @@ -251,11 +254,102 @@ def test_remove(self): a_to_z = list(chr(i) for i in xrange(ord('a'), ord('z') + 1)) b_to_z_by_2 = list(chr(i) for i in xrange(ord('b'), ord('z') + 1, 2)) - jl = ArrayList(a_to_z) + jl = self.type2test(a_to_z) for i in xrange(13): jl.remove(i) self.assertEqual(jl, b_to_z_by_2) + def test_concat(self): + # See http://bugs.jython.org/issue2688 + lst = ArrayList([1, 2, 3]) + lst2 = [4, 5, 6] + self.assertEquals(lst+lst2, [1, 2, 3, 4, 5, 6]) + self.assertEquals(lst2+lst, [4, 5, 6, 1, 2, 3]) + + def test_equality_empty_list(self): + jl = self.type2test() + self.assertTrue(jl == []) + self.assertTrue([] == jl) + + def test_equality_simple_list(self): + jl = self.type2test() + self.assertFalse(jl == [1]) + self.assertFalse([1] == jl) + + def test_equality_mixed_types_list(self): + ref = [False, 1, 3**9, "3"] + alt = [0, True, 3L**9, u"3"] + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + + for v in [ref, alt, jref]: + self.assertTrue(jref == v) + self.assertTrue(v == jref) + self.assertTrue(jref == self.type2test(v)) + + alt = [False, 1, 2e4, "3"] + for v in [alt, ref[:-1], ref+[{}], []]: + self.assertFalse(jref == v) + self.assertFalse(v == jref) + self.assertFalse(jref == self.type2test(v)) + + # Test for http://bugs.jython.org/issue2639 + # This is to test the != comparisons between Java and Python lists + def test_inequality_empty_list(self): + jl = self.type2test() + self.assertFalse(jl != []) + self.assertFalse([] != jl) + + def test_inequality_simple_list(self): + jl = self.type2test() + self.assertTrue(jl != [1]) + self.assertTrue([1] != jl) + + def test_inequality_mixed_types_list(self): + ref = [False, 1, 3**9, "3"] + alt = [0, True, 3L**9, u"3"] + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + + for v in [ref, alt, jref]: + self.assertFalse(jref != v) + self.assertFalse(v != jref) + self.assertFalse(jref != self.type2test(v)) + + alt = [False, 1, 2e4, "3"] + for v in [alt, ref[:-1], ref+[{}], []]: + self.assertTrue(jref != v) + self.assertTrue(v != jref) + self.assertTrue(jref != self.type2test(v)) + + +class JavaArrayListTestCase(JavaListTestCase): + type2test = ArrayList + + +class JavaLinkedListTestCase(JavaListTestCase): + type2test = LinkedList + + @unittest.skip("Fails for LinkedList see http://bugs.jython.org/issue2645") + def test_pop(self): + pass + + @unittest.skip("Seems to hang for linked list") + def test_bigrepeat(self): + pass + + @unittest.skip("Takes a long time and can cause OutOfMemory") + def test_overflow(self): + pass + + +class JavaVectorTestCase(JavaListTestCase): + type2test = Vector + + @unittest.skip("Takes a long time and can cause OutOfMemory") + def test_bigrepeat(self): + pass + class ListSubclassTestCase(unittest.TestCase): @@ -298,11 +392,13 @@ def __getitem__(self, index): def test_main(): - test_support.run_unittest(ListSubclassTestCase, - ListTestCase, + test_support.run_unittest(ListTestCase, ThreadSafetyTestCase, ExtendedSliceTestCase, - JavaListTestCase) - + JavaArrayListTestCase, + JavaLinkedListTestCase, + JavaVectorTestCase, + ListSubclassTestCase) + if __name__ == "__main__": test_main() diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index b6ae68fea..17a802953 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -1,7 +1,6 @@ #!/usr/bin/env python -# -*- coding: iso-8859-1 -*- +# -*- coding: utf-8 -*- -from __future__ import with_statement from test import test_support import marshal import sys @@ -118,7 +117,7 @@ def test_floats(self): class StringTestCase(unittest.TestCase): def test_unicode(self): - for s in [u"", u"Andr Previn", u"abc", u" "*10000]: + for s in [u"", u"André Previn", u"abc", u" "*10000]: new = marshal.loads(marshal.dumps(s)) self.assertEqual(s, new) self.assertEqual(type(s), type(new)) @@ -128,7 +127,7 @@ def test_unicode(self): os.unlink(test_support.TESTFN) def test_string(self): - for s in ["", "Andr Previn", "abc", " "*10000]: + for s in ["", "André Previn", "abc", " "*10000]: new = marshal.loads(marshal.dumps(s)) self.assertEqual(s, new) self.assertEqual(type(s), type(new)) @@ -137,27 +136,28 @@ def test_string(self): self.assertEqual(type(s), type(new)) os.unlink(test_support.TESTFN) - if not test_support.is_jython: - def test_buffer(self): - for s in ["", "Andr Previn", "abc", " "*10000]: + def test_buffer(self): + for s in ["", "André Previn", "abc", " "*10000]: + with test_support.check_py3k_warnings(("buffer.. not supported", + DeprecationWarning)): b = buffer(s) - new = marshal.loads(marshal.dumps(b)) - self.assertEqual(s, new) - new = roundtrip(b) - self.assertEqual(s, new) - os.unlink(test_support.TESTFN) + new = marshal.loads(marshal.dumps(b)) + self.assertEqual(s, new) + new = roundtrip(b) + self.assertEqual(s, new) + os.unlink(test_support.TESTFN) class ExceptionTestCase(unittest.TestCase): def test_exceptions(self): new = marshal.loads(marshal.dumps(StopIteration)) self.assertEqual(StopIteration, new) +@unittest.skipIf(test_support.is_jython, "requires PBC compilation back-end") class CodeTestCase(unittest.TestCase): - if not test_support.is_jython: # XXX - need to use the PBC compilation backend, which doesn't exist yet - def test_code(self): - co = ExceptionTestCase.test_exceptions.func_code - new = marshal.loads(marshal.dumps(co)) - self.assertEqual(co, new) + def test_code(self): + co = ExceptionTestCase.test_exceptions.func_code + new = marshal.loads(marshal.dumps(co)) + self.assertEqual(co, new) class ContainerTestCase(unittest.TestCase): d = {'astring': 'foo@bar.baz.spam', @@ -167,7 +167,7 @@ class ContainerTestCase(unittest.TestCase): 'alist': ['.zyx.41'], 'atuple': ('.zyx.41',)*10, 'aboolean': False, - 'aunicode': u"Andr Previn" + 'aunicode': u"André Previn" } def test_dict(self): new = marshal.loads(marshal.dumps(self.d)) @@ -197,7 +197,7 @@ def test_sets(self): t = constructor(self.d.keys()) new = marshal.loads(marshal.dumps(t)) self.assertEqual(t, new) - self.assert_(isinstance(new, constructor)) + self.assertTrue(isinstance(new, constructor)) self.assertNotEqual(id(t), id(new)) new = roundtrip(t) self.assertEqual(t, new) @@ -215,8 +215,8 @@ def test_patch_873224(self): def test_version_argument(self): # Python 2.4.0 crashes for any call to marshal.dumps(x, y) - self.assertEquals(marshal.loads(marshal.dumps(5, 0)), 5) - self.assertEquals(marshal.loads(marshal.dumps(5, 1)), 5) + self.assertEqual(marshal.loads(marshal.dumps(5, 0)), 5) + self.assertEqual(marshal.loads(marshal.dumps(5, 1)), 5) def test_fuzz(self): # simple test that it's at least not *totally* trivial to @@ -251,6 +251,77 @@ def test_recursion_limit(self): last.append([0]) self.assertRaises(ValueError, marshal.dumps, head) + def test_exact_type_match(self): + # Former bug: + # >>> class Int(int): pass + # >>> type(loads(dumps(Int()))) + # + for typ in (int, long, float, complex, tuple, list, dict, set, frozenset): + # Note: str and unicode subclasses are not tested because they get handled + # by marshal's routines for objects supporting the buffer API. + subtyp = type('subtyp', (typ,), {}) + self.assertRaises(ValueError, marshal.dumps, subtyp()) + + # Issue #1792 introduced a change in how marshal increases the size of its + # internal buffer; this test ensures that the new code is exercised. + def test_large_marshal(self): + size = int(1e6) + testString = 'abc' * size + marshal.dumps(testString) + + def test_invalid_longs(self): + # Issue #7019: marshal.loads shouldn't produce unnormalized PyLongs + invalid_string = 'l\x02\x00\x00\x00\x00\x00\x00\x00' + self.assertRaises(ValueError, marshal.loads, invalid_string) + +LARGE_SIZE = 2**31 +character_size = 4 if sys.maxunicode > 0xFFFF else 2 +pointer_size = 8 if sys.maxsize > 0xFFFFFFFF else 4 + +@unittest.skipIf(LARGE_SIZE > sys.maxsize, "requires larger sys.maxsize") +class LargeValuesTestCase(unittest.TestCase): + def check_unmarshallable(self, data): + f = open(test_support.TESTFN, 'wb') + self.addCleanup(test_support.unlink, test_support.TESTFN) + with f: + self.assertRaises(ValueError, marshal.dump, data, f) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + def test_string(self, size): + self.check_unmarshallable('x' * size) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, + memuse=character_size, dry_run=False) + def test_unicode(self, size): + self.check_unmarshallable(u'x' * size) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, + memuse=pointer_size, dry_run=False) + def test_tuple(self, size): + self.check_unmarshallable((None,) * size) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, + memuse=pointer_size, dry_run=False) + def test_list(self, size): + self.check_unmarshallable([None] * size) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, + memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1), + dry_run=False) + def test_set(self, size): + self.check_unmarshallable(set(range(size))) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, + memuse=pointer_size*12 + sys.getsizeof(LARGE_SIZE-1), + dry_run=False) + def test_frozenset(self, size): + self.check_unmarshallable(frozenset(range(size))) + + @test_support.precisionbigmemtest(size=LARGE_SIZE, memuse=1, dry_run=False) + def test_bytearray(self, size): + self.check_unmarshallable(bytearray(size)) + + def test_main(): test_support.run_unittest(IntTestCase, FloatTestCase, @@ -258,7 +329,9 @@ def test_main(): CodeTestCase, ContainerTestCase, ExceptionTestCase, - BugsTestCase) + BugsTestCase, + LargeValuesTestCase, + ) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py index 757d1850a..b5dbbc9ec 100644 --- a/Lib/test/test_memoryio.py +++ b/Lib/test/test_memoryio.py @@ -398,13 +398,6 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase): UnsupportedOperation = pyio.UnsupportedOperation - # When Jython tries to use UnsupportedOperation as _pyio defines it, it runs - # into a problem with multiple inheritance and the slots array: issue 1996. - # Override the affected test version just so we can skip it visibly. - @unittest.skipIf(support.is_jython, "FIXME: Jython issue 1996") - def test_detach(self): - pass - @staticmethod def buftype(s): return s.encode("ascii") @@ -595,13 +588,6 @@ class PyStringIOTest(MemoryTestMixin, MemorySeekTestMixin, UnsupportedOperation = pyio.UnsupportedOperation EOF = "" - # When Jython tries to use UnsupportedOperation as _pyio defines it, it runs - # into a problem with multiple inheritance and the slots array: issue 1996. - # Override the affected test version just so we can skip it visibly. - @unittest.skipIf(support.is_jython, "FIXME: Jython issue 1996") - def test_detach(self): - pass - class PyStringIOPickleTest(TextIOTestMixin, unittest.TestCase): """Test if pickle restores properly the internal state of StringIO. @@ -625,10 +611,6 @@ class CBytesIOTest(PyBytesIOTest): "array.array() does not have the new buffer API" )(PyBytesIOTest.test_bytes_array) - # Re-instate test_detach skipped by Jython in PyBytesIOTest - if support.is_jython: # FIXME: Jython issue 1996 - test_detach = MemoryTestMixin.test_detach - def test_getstate(self): memio = self.ioclass() state = memio.__getstate__() @@ -673,10 +655,6 @@ class CStringIOTest(PyStringIOTest): # XXX: For the Python version of io.StringIO, this is highly # dependent on the encoding used for the underlying buffer. - # Re-instate test_detach skipped by Jython in PyBytesIOTest - if support.is_jython: # FIXME: Jython issue 1996 - test_detach = MemoryTestMixin.test_detach - # This test checks that tell() results are consistent with the length of # text written, but this is not documented in the API: only that seek() # accept what tell() returns. diff --git a/Lib/test/test_os_jy.py b/Lib/test/test_os_jy.py index 8217cb31d..640408815 100644 --- a/Lib/test/test_os_jy.py +++ b/Lib/test/test_os_jy.py @@ -198,56 +198,105 @@ class UnicodeTestCase(unittest.TestCase): def test_env(self): with test_support.temp_cwd(name=u"tempcwd-中文"): + # os.environ is constructed with FS-encoded values (as in CPython), + # but it will accept unicode additions. newenv = os.environ.copy() - newenv["TEST_HOME"] = u"首页" - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(os.getenv("TEST_HOME").encode("utf-8"))'], - stdout=subprocess.PIPE, - env=newenv) - self.assertEqual(p.stdout.read().decode("utf-8"), u"首页") + newenv["TEST_HOME"] = expected = u"首页" + # Environment passed as UTF-16 String[] by Java, arrives FS-encoded. + for encoding in ('utf-8', 'gbk'): + # Emit the value of TEST_HOME explicitly encoded. + p = subprocess.Popen( + [sys.executable, "-c", + 'import sys, os;' \ + 'sys.stdout.write(os.getenv("TEST_HOME")' \ + '.decode(sys.getfilesystemencoding())' \ + '.encode("%s"))' \ + % encoding], + stdout=subprocess.PIPE, + env=newenv) + # Decode with chosen encoding + self.assertEqual(p.stdout.read().decode(encoding), u"首页") + + def test_env_naively(self): + with test_support.temp_cwd(name=u"tempcwd-中文"): + # os.environ is constructed with FS-encoded values (as in CPython), + # but it will accept unicode additions. + newenv = os.environ.copy() + newenv["TEST_HOME"] = expected = u"首页" + # Environment passed as UTF-16 String[] by Java, arrives FS-encoded. + # However, emit TEST_HOME without thinking about the encoding. + p = subprocess.Popen( + [sys.executable, "-c", + 'import sys, os;' \ + 'sys.stdout.write(os.getenv("TEST_HOME"))'], + stdout=subprocess.PIPE, + env=newenv) + # Decode with FS encoding used by subprocess communication + self.assertEqual(p.stdout.read().decode('utf-8'), expected) def test_getcwd(self): with test_support.temp_cwd(name=u"tempcwd-中文") as temp_cwd: - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(os.getcwd().encode("utf-8"))'], - stdout=subprocess.PIPE) - self.assertEqual(p.stdout.read().decode("utf-8"), temp_cwd) + # os.getcwd reports the working directory as an FS-encoded str, + # which is also the encoding used in subprocess communication. + p = subprocess.Popen([ + sys.executable, "-c", + 'import sys,os;' \ + 'sys.stdout.write(os.getcwd())'], + stdout=subprocess.PIPE) + self.assertEqual(p.stdout.read(), temp_cwd) + + def test_getcwdu(self): + with test_support.temp_cwd(name=u"tempcwd-中文") as temp_cwd: + # os.getcwdu reports the working directory as unicode, + # which must be encoded for subprocess communication. + p = subprocess.Popen([ + sys.executable, "-c", + 'import sys,os;' \ + 'sys.stdout.write(os.getcwdu().encode(sys.getfilesystemencoding()))'], + stdout=subprocess.PIPE) + self.assertEqual(p.stdout.read(), temp_cwd) def test_listdir(self): - # It is hard to avoid Unicode paths on systems like OS X. Use - # relative paths from a temp CWD to work around this + # It is hard to avoid Unicode paths on systems like OS X. Use relative + # paths from a temp CWD to work around this. But when you don't, + # it behaves like this ... with test_support.temp_cwd() as new_cwd: - unicode_path = os.path.join(".", "unicode") - self.assertIs(type(unicode_path), str) - chinese_path = os.path.join(unicode_path, u"中文") + + basedir = os.path.join(".", "unicode") + self.assertIs(type(basedir), bytes) + chinese_path = os.path.join(basedir, u"中文") self.assertIs(type(chinese_path), unicode) home_path = os.path.join(chinese_path, u"首页") os.makedirs(home_path) + FS = sys.getfilesystemencoding() + with open(os.path.join(home_path, "test.txt"), "w") as test_file: test_file.write("42\n") - # Verify works with str paths, returning Unicode as necessary - entries = os.listdir(unicode_path) - self.assertIn(u"中文", entries) + # listdir(bytes) includes encoded form of 中文 + entries = os.listdir(basedir) + self.assertIn(u"中文".encode(FS), entries) + for entry in entries: + self.assertIs(type(entry), bytes) - # Verify works with Unicode paths + # listdir(unicode) includes unicode form of 首页 entries = os.listdir(chinese_path) self.assertIn(u"首页", entries) + for entry in entries: + self.assertIs(type(entry), unicode) # glob.glob builds on os.listdir; note that we don't use - # Unicode paths in the arg to glob + # Unicode paths in the arg to glob so the result is bytes self.assertEqual( glob.glob(os.path.join("unicode", "*")), - [os.path.join(u"unicode", u"中文")]) + [os.path.join(u"unicode", u"中文").encode(FS)]) self.assertEqual( glob.glob(os.path.join("unicode", "*", "*")), - [os.path.join(u"unicode", u"中文", u"首页")]) + [os.path.join(u"unicode", u"中文", u"首页").encode(FS)]) self.assertEqual( glob.glob(os.path.join("unicode", "*", "*", "*")), - [os.path.join(u"unicode", u"中文", u"首页", "test.txt")]) + [os.path.join(u"unicode", u"中文", u"首页", "test.txt").encode(FS)]) # Now use a Unicode path as well as in the glob arg self.assertEqual( @@ -263,11 +312,27 @@ def test_listdir(self): # Verify Java integration. But we will need to construct # an absolute path since chdir doesn't work with Java # (except for subprocesses, like below in test_env) - for entry in entries: + for entry in entries: # list(unicode) + # new_cwd is bytes while chinese_path is unicode. + # But new_cwd is not guaranteed to be just ascii, so decode it. + new_cwd = new_cwd.decode(FS) entry_path = os.path.join(new_cwd, chinese_path, entry) f = File(entry_path) - self.assertTrue(f.exists(), "File %r (%r) should be testable for existence" % ( - f, entry_path)) + self.assertTrue(f.exists(), + "File %r (%r) should be testable for existence" % + (f, entry_path)) + + def test_uname(self): + # Test that os.uname returns a tuple of (arbitrary) strings. + # uname failed on on a Chinese localised system (see + # https://bugs.jython.org/issue2726). This test really needs to + # run in that environment or it passes too easily. + result = os.uname() + # (sysname, nodename, release, version, machine) + self.assertEqual(type(result), tuple) + self.assertEqual(len(result), 5) + for s in result: self.assertEqual(type(s), str) + class LocaleTestCase(unittest.TestCase): @@ -292,6 +357,7 @@ def normalize(code): return available_codes # must be on posix and turkish locale supported + @unittest.skipIf(not test_support.is_jython_posix, "Not posix") def test_turkish_locale_posix_module(self): # Verifies fix of http://bugs.jython.org/issue1874 self.get_installed_locales(["tr_TR.UTF-8"], "Turkish locale not installed, cannot test") @@ -320,8 +386,8 @@ def test_turkish_locale_string_lower_upper(self): # # Note that JVMs seem to have some latitude here however, so support # either for now. - ["['i', u'\\u0131', 'I', u'\\u0130']\n", - "['i', u'i', 'I', u'I']\n"]) + ["['i', u'\\u0131', 'I', u'\\u0130']" + os.linesep, + "['i', u'i', 'I', u'I']" + os.linesep]) def test_strptime_locale(self): # Verifies fix of http://bugs.jython.org/issue2261 @@ -336,20 +402,26 @@ def test_strptime_locale(self): [sys.executable, "-c", 'import datetime; print(datetime.datetime.strptime("2015-01-22", "%Y-%m-%d"))'], env=newenv), - "2015-01-22 00:00:00\n") + "2015-01-22 00:00:00" + os.linesep) def test_strftime_japanese_locale(self): # Verifies fix of http://bugs.jython.org/issue2301 - produces # UTF-8 encoded output per what CPython does, rather than Unicode. # We will revisit in Jython 3.x! self.get_installed_locales("ja_JP.UTF-8") + if test_support.get_java_version() < (10,): + expected = "'\\xe6\\x97\\xa5 3 29 14:55:13 2015'" + else: + # From Java 10 onwards, Japanese formatting more correctly includes + # 月, the kanji character for month + expected = "'\\xe6\\x97\\xa5 3\\xe6\\x9c\\x88 29 14:55:13 2015'" self.assertEqual( subprocess.check_output( [sys.executable, "-J-Duser.country=JP", "-J-Duser.language=ja", "-c", "import time; print repr(time.strftime('%c', (2015, 3, 29, 14, 55, 13, 6, 88, 0)))"]), - "'\\xe6\\x97\\xa5 3 29 14:55:13 2015'\n") + expected + os.linesep) class SystemTestCase(unittest.TestCase): diff --git a/Lib/test/test_pbcvm.py b/Lib/test/test_pbcvm.py index a6d293e92..597c522c4 100644 --- a/Lib/test/test_pbcvm.py +++ b/Lib/test/test_pbcvm.py @@ -7,18 +7,26 @@ def make_fib_function(): from org.python.core import PyBytecode, PyFunction + + # The code below was compiled from + # def fib(x): + # if x == 0 or x == 1: + # return 1 + # else: + # return fib(x-1)+fib(x-2) + co_argcount = 1 co_nlocals = 1 co_stacksize = 4 co_flags = 67 - co_code = '|\x00\x00d\x01\x00j\x02\x00p\r\x00\x01|\x00\x00d\x02\x00j\x02\x00o\x08\x00\x01d\x02\x00Sn\x1d\x00\x01t\x00\x00|\x00\x00d\x03\x00\x18\x83\x01\x00t\x00\x00|\x00\x00d\x02\x00\x18\x83\x01\x00\x17Sd\x00\x00S' + co_code = '|\x00\x00d\x01\x00k\x02\x00s\x18\x00|\x00\x00d\x02\x00k\x02\x00r\x1c\x00d\x02\x00St\x00\x00|\x00\x00d\x02\x00\x18\x83\x01\x00t\x00\x00|\x00\x00d\x03\x00\x18\x83\x01\x00\x17Sd\x00\x00S' co_consts = (None, 0, 1, 2) co_names = ('fib',) co_varnames = ('x',) co_filename = '' co_name = 'fib' co_firstlineno = 1 - co_lnotab = '\x00\x01\x1a\x01\x08\x02' + co_lnotab = '\x00\x01\x18\x01\x04\x02' co_freevars = () co_cellvars = () @@ -73,3 +81,4 @@ def test_main(): if __name__ == "__main__": test_main() + diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py index 577167283..62e24dfc4 100644 --- a/Lib/test/test_platform.py +++ b/Lib/test/test_platform.py @@ -136,6 +136,7 @@ def test_uname(self): self.assertTrue(any(res)) @unittest.skipUnless(sys.platform.startswith('win'), "windows only test") + # One may enable this for Jython, but must disable the cache in os.uname() to pass. def test_uname_win32_ARCHITEW6432(self): # Issue 7860: make sure we get architecture from the correct variable # on 64 bit Windows: if PROCESSOR_ARCHITEW6432 exists we should be diff --git a/Lib/test/test_runpy.py b/Lib/test/test_runpy.py deleted file mode 100644 index d83118f98..000000000 --- a/Lib/test/test_runpy.py +++ /dev/null @@ -1,402 +0,0 @@ -# Test the runpy module -import unittest -import os -import os.path -import sys -import re -import tempfile -from test.test_support import verbose, run_unittest, forget -from test.script_helper import (temp_dir, make_script, compile_script, - make_pkg, make_zip_script, make_zip_pkg) - - -from runpy import _run_code, _run_module_code, run_module, run_path -# Note: This module can't safely test _run_module_as_main as it -# runs its tests in the current process, which would mess with the -# real __main__ module (usually test.regrtest) -# See test_cmd_line_script for a test that executes that code path - -# Set up the test code and expected results - -class RunModuleCodeTest(unittest.TestCase): - """Unit tests for runpy._run_code and runpy._run_module_code""" - - expected_result = ["Top level assignment", "Lower level reference"] - test_source = ( - "# Check basic code execution\n" - "result = ['Top level assignment']\n" - "def f():\n" - " result.append('Lower level reference')\n" - "f()\n" - "# Check the sys module\n" - "import sys\n" - "run_argv0 = sys.argv[0]\n" - "run_name_in_sys_modules = __name__ in sys.modules\n" - "if run_name_in_sys_modules:\n" - " module_in_sys_modules = globals() is sys.modules[__name__].__dict__\n" - "# Check nested operation\n" - "import runpy\n" - "nested = runpy._run_module_code('x=1\\n', mod_name='')\n" - ) - - def test_run_code(self): - saved_argv0 = sys.argv[0] - d = _run_code(self.test_source, {}) - self.assertEqual(d["result"], self.expected_result) - self.assertIs(d["__name__"], None) - self.assertIs(d["__file__"], None) - self.assertIs(d["__loader__"], None) - self.assertIs(d["__package__"], None) - self.assertIs(d["run_argv0"], saved_argv0) - self.assertNotIn("run_name", d) - self.assertIs(sys.argv[0], saved_argv0) - - def test_run_module_code(self): - initial = object() - name = "" - file = "Some other nonsense" - loader = "Now you're just being silly" - package = '' # Treat as a top level module - d1 = dict(initial=initial) - saved_argv0 = sys.argv[0] - d2 = _run_module_code(self.test_source, - d1, - name, - file, - loader, - package) - self.assertNotIn("result", d1) - self.assertIs(d2["initial"], initial) - self.assertEqual(d2["result"], self.expected_result) - self.assertEqual(d2["nested"]["x"], 1) - self.assertIs(d2["__name__"], name) - self.assertTrue(d2["run_name_in_sys_modules"]) - self.assertTrue(d2["module_in_sys_modules"]) - self.assertIs(d2["__file__"], file) - self.assertIs(d2["run_argv0"], file) - self.assertIs(d2["__loader__"], loader) - self.assertIs(d2["__package__"], package) - self.assertIs(sys.argv[0], saved_argv0) - self.assertNotIn(name, sys.modules) - - -class RunModuleTest(unittest.TestCase): - """Unit tests for runpy.run_module""" - - def expect_import_error(self, mod_name): - try: - run_module(mod_name) - except ImportError: - pass - else: - self.fail("Expected import error for " + mod_name) - - def test_invalid_names(self): - # Builtin module - self.expect_import_error("sys") - # Non-existent modules - self.expect_import_error("sys.imp.eric") - self.expect_import_error("os.path.half") - self.expect_import_error("a.bee") - self.expect_import_error(".howard") - self.expect_import_error("..eaten") - # Package without __main__.py - self.expect_import_error("multiprocessing") - - def test_library_module(self): - run_module("runpy") - - def _add_pkg_dir(self, pkg_dir): - os.mkdir(pkg_dir) - pkg_fname = os.path.join(pkg_dir, "__init__"+os.extsep+"py") - pkg_file = open(pkg_fname, "w") - pkg_file.close() - return pkg_fname - - def _make_pkg(self, source, depth, mod_base="runpy_test"): - pkg_name = "__runpy_pkg__" - test_fname = mod_base+os.extsep+"py" - pkg_dir = sub_dir = tempfile.mkdtemp() - if verbose: print " Package tree in:", sub_dir - sys.path.insert(0, pkg_dir) - if verbose: print " Updated sys.path:", sys.path[0] - for i in range(depth): - sub_dir = os.path.join(sub_dir, pkg_name) - pkg_fname = self._add_pkg_dir(sub_dir) - if verbose: print " Next level in:", sub_dir - if verbose: print " Created:", pkg_fname - mod_fname = os.path.join(sub_dir, test_fname) - mod_file = open(mod_fname, "w") - mod_file.write(source) - mod_file.close() - if verbose: print " Created:", mod_fname - mod_name = (pkg_name+".")*depth + mod_base - return pkg_dir, mod_fname, mod_name - - def _del_pkg(self, top, depth, mod_name): - for entry in list(sys.modules): - if entry.startswith("__runpy_pkg__"): - del sys.modules[entry] - if verbose: print " Removed sys.modules entries" - del sys.path[0] - if verbose: print " Removed sys.path entry" - for root, dirs, files in os.walk(top, topdown=False): - for name in files: - try: - os.remove(os.path.join(root, name)) - except OSError, ex: - if verbose: print ex # Persist with cleaning up - for name in dirs: - fullname = os.path.join(root, name) - try: - os.rmdir(fullname) - except OSError, ex: - if verbose: print ex # Persist with cleaning up - try: - os.rmdir(top) - if verbose: print " Removed package tree" - except OSError, ex: - if verbose: print ex # Persist with cleaning up - - def _check_module(self, depth): - pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth)) - forget(mod_name) - try: - if verbose: print "Running from source:", mod_name - d1 = run_module(mod_name) # Read from source - self.assertIn("x", d1) - self.assertTrue(d1["x"] == 1) - del d1 # Ensure __loader__ entry doesn't keep file open - __import__(mod_name) - os.remove(mod_fname) - if verbose: print "Running from compiled:", mod_name - d2 = run_module(mod_name) # Read from bytecode - self.assertIn("x", d2) - self.assertTrue(d2["x"] == 1) - del d2 # Ensure __loader__ entry doesn't keep file open - finally: - self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print "Module executed successfully" - - def _check_package(self, depth): - pkg_dir, mod_fname, mod_name = ( - self._make_pkg("x=1\n", depth, "__main__")) - pkg_name, _, _ = mod_name.rpartition(".") - forget(mod_name) - try: - if verbose: print "Running from source:", pkg_name - d1 = run_module(pkg_name) # Read from source - self.assertIn("x", d1) - self.assertTrue(d1["x"] == 1) - del d1 # Ensure __loader__ entry doesn't keep file open - __import__(mod_name) - os.remove(mod_fname) - if verbose: print "Running from compiled:", pkg_name - d2 = run_module(pkg_name) # Read from bytecode - self.assertIn("x", d2) - self.assertTrue(d2["x"] == 1) - del d2 # Ensure __loader__ entry doesn't keep file open - finally: - self._del_pkg(pkg_dir, depth, pkg_name) - if verbose: print "Package executed successfully" - - def _add_relative_modules(self, base_dir, source, depth): - if depth <= 1: - raise ValueError("Relative module test needs depth > 1") - pkg_name = "__runpy_pkg__" - module_dir = base_dir - for i in range(depth): - parent_dir = module_dir - module_dir = os.path.join(module_dir, pkg_name) - # Add sibling module - sibling_fname = os.path.join(module_dir, "sibling"+os.extsep+"py") - sibling_file = open(sibling_fname, "w") - sibling_file.close() - if verbose: print " Added sibling module:", sibling_fname - # Add nephew module - uncle_dir = os.path.join(parent_dir, "uncle") - self._add_pkg_dir(uncle_dir) - if verbose: print " Added uncle package:", uncle_dir - cousin_dir = os.path.join(uncle_dir, "cousin") - self._add_pkg_dir(cousin_dir) - if verbose: print " Added cousin package:", cousin_dir - nephew_fname = os.path.join(cousin_dir, "nephew"+os.extsep+"py") - nephew_file = open(nephew_fname, "w") - nephew_file.close() - if verbose: print " Added nephew module:", nephew_fname - - def _check_relative_imports(self, depth, run_name=None): - contents = r"""\ -from __future__ import absolute_import -from . import sibling -from ..uncle.cousin import nephew -""" - pkg_dir, mod_fname, mod_name = ( - self._make_pkg(contents, depth)) - try: - self._add_relative_modules(pkg_dir, contents, depth) - pkg_name = mod_name.rpartition('.')[0] - if verbose: print "Running from source:", mod_name - d1 = run_module(mod_name, run_name=run_name) # Read from source - self.assertIn("__package__", d1) - self.assertTrue(d1["__package__"] == pkg_name) - self.assertIn("sibling", d1) - self.assertIn("nephew", d1) - del d1 # Ensure __loader__ entry doesn't keep file open - __import__(mod_name) - os.remove(mod_fname) - if verbose: print "Running from compiled:", mod_name - d2 = run_module(mod_name, run_name=run_name) # Read from bytecode - self.assertIn("__package__", d2) - self.assertTrue(d2["__package__"] == pkg_name) - self.assertIn("sibling", d2) - self.assertIn("nephew", d2) - del d2 # Ensure __loader__ entry doesn't keep file open - finally: - self._del_pkg(pkg_dir, depth, mod_name) - if verbose: print "Module executed successfully" - - def test_run_module(self): - for depth in range(4): - if verbose: print "Testing package depth:", depth - self._check_module(depth) - - def test_run_package(self): - for depth in range(1, 4): - if verbose: print "Testing package depth:", depth - self._check_package(depth) - - def test_explicit_relative_import(self): - for depth in range(2, 5): - if verbose: print "Testing relative imports at depth:", depth - self._check_relative_imports(depth) - - def test_main_relative_import(self): - for depth in range(2, 5): - if verbose: print "Testing main relative imports at depth:", depth - self._check_relative_imports(depth, "__main__") - - -class RunPathTest(unittest.TestCase): - """Unit tests for runpy.run_path""" - # Based on corresponding tests in test_cmd_line_script - - test_source = """\ -# Script may be run with optimisation enabled, so don't rely on assert -# statements being executed -def assertEqual(lhs, rhs): - if lhs != rhs: - raise AssertionError('%r != %r' % (lhs, rhs)) -def assertIs(lhs, rhs): - if lhs is not rhs: - raise AssertionError('%r is not %r' % (lhs, rhs)) -# Check basic code execution -result = ['Top level assignment'] -def f(): - result.append('Lower level reference') -f() -assertEqual(result, ['Top level assignment', 'Lower level reference']) -# Check the sys module -import sys -assertIs(globals(), sys.modules[__name__].__dict__) -argv0 = sys.argv[0] -""" - - def _make_test_script(self, script_dir, script_basename, source=None): - if source is None: - source = self.test_source - return make_script(script_dir, script_basename, source) - - def _check_script(self, script_name, expected_name, expected_file, - expected_argv0, expected_package): - result = run_path(script_name) - self.assertEqual(result["__name__"], expected_name) - self.assertEqual(result["__file__"], expected_file) - self.assertIn("argv0", result) - self.assertEqual(result["argv0"], expected_argv0) - self.assertEqual(result["__package__"], expected_package) - - def _check_import_error(self, script_name, msg): - msg = re.escape(msg) - self.assertRaisesRegexp(ImportError, msg, run_path, script_name) - - def test_basic_script(self): - with temp_dir() as script_dir: - mod_name = 'script' - script_name = self._make_test_script(script_dir, mod_name) - self._check_script(script_name, "", script_name, - script_name, None) - - def test_script_compiled(self): - with temp_dir() as script_dir: - mod_name = 'script' - script_name = self._make_test_script(script_dir, mod_name) - compiled_name = compile_script(script_name) - os.remove(script_name) - self._check_script(compiled_name, "", compiled_name, - compiled_name, None) - - def test_directory(self): - with temp_dir() as script_dir: - mod_name = '__main__' - script_name = self._make_test_script(script_dir, mod_name) - self._check_script(script_dir, "", script_name, - script_dir, '') - - def test_directory_compiled(self): - with temp_dir() as script_dir: - mod_name = '__main__' - script_name = self._make_test_script(script_dir, mod_name) - compiled_name = compile_script(script_name) - os.remove(script_name) - self._check_script(script_dir, "", compiled_name, - script_dir, '') - - def test_directory_error(self): - with temp_dir() as script_dir: - mod_name = 'not_main' - script_name = self._make_test_script(script_dir, mod_name) - msg = "can't find '__main__' module in %r" % script_dir - self._check_import_error(script_dir, msg) - - def test_zipfile(self): - with temp_dir() as script_dir: - mod_name = '__main__' - script_name = self._make_test_script(script_dir, mod_name) - zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) - self._check_script(zip_name, "", fname, zip_name, '') - - def test_zipfile_compiled(self): - with temp_dir() as script_dir: - mod_name = '__main__' - script_name = self._make_test_script(script_dir, mod_name) - compiled_name = compile_script(script_name) - zip_name, fname = make_zip_script(script_dir, 'test_zip', compiled_name) - self._check_script(zip_name, "", fname, zip_name, '') - - def test_zipfile_error(self): - with temp_dir() as script_dir: - mod_name = 'not_main' - script_name = self._make_test_script(script_dir, mod_name) - zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) - msg = "can't find '__main__' module in '%s'" % zip_name - self._check_import_error(zip_name, msg) - - def test_main_recursion_error(self): - with temp_dir() as script_dir, temp_dir() as dummy_dir: - mod_name = '__main__' - source = ("import runpy\n" - "runpy.run_path(%r)\n") % dummy_dir - script_name = self._make_test_script(script_dir, mod_name, source) - zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) - msg = "recursion depth exceeded" - self.assertRaisesRegexp(RuntimeError, msg, run_path, zip_name) - - - -def test_main(): - run_unittest(RunModuleCodeTest, RunModuleTest, RunPathTest) - -if __name__ == "__main__": - test_main() diff --git a/Lib/test/test_select.py b/Lib/test/test_select.py index 226ebd872..00a32f9c0 100644 --- a/Lib/test/test_select.py +++ b/Lib/test/test_select.py @@ -6,13 +6,18 @@ import select import socket import sys -import test_socket +from test import test_socket import unittest from test import test_support HOST = test_socket.HOST PORT = test_socket.PORT + 100 +if test_support.is_jython: + import java.util.logging + from test.test_socket import _set_java_logging + + class SelectWrapper: def __init__(self): @@ -179,6 +184,13 @@ def test_cpython_compatible_select_exists(self): def test_main(): + if test_support.is_jython: + # Netty logs stack dumps when we destroy sockets after their parent + # group, see http://bugs.jython.org/issue2517 . Is this a real bug? + # For now, treat as inconvenient artifact of test. + _set_java_logging("io.netty.channel.ChannelInitializer", + java.util.logging.Level.SEVERE) + tests = [TestSelectInvalidParameters, TestSelectClientSocket, TestPollClientSocket, diff --git a/Lib/test/test_set_jy.py b/Lib/test/test_set_jy.py index 18bbe52da..73ac73ed6 100644 --- a/Lib/test/test_set_jy.py +++ b/Lib/test/test_set_jy.py @@ -84,7 +84,7 @@ def test_serialization(self): class TestJavaSet(test_set.TestSet): - thetype = HashSet + type2test = HashSet def test_init(self): # Instances of Java types cannot be re-initialized @@ -102,18 +102,83 @@ def test_pickling(self): dup = pickle.loads(p) self.assertEqual(self.s, dup, "%s != %s" % (self.s, dup)) + def test_equality_empty_set(self): + js = self.type2test() + self.assertTrue(js == set()) + self.assertTrue(set() == js) + + def test_equality_simple_set(self): + js = self.type2test() + self.assertFalse(js == set([1])) + self.assertFalse(set([1]) == js) + + def test_equality_mixed_types_set(self): + ref = {False, 1, 3**9, "3"} + alt = {0, True, 3L**9, u"3"} + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + for v in [ref, alt, jref]: + self.assertTrue(jref == v) + self.assertTrue(v == jref) + self.assertTrue(jref == self.type2test(v)) + self.assertTrue(self.type2test(v) == jref) + + alt1 = {False, 1.01, 3**9, "3"} + alt2 = {False, 1, "3"}; + alt3 = {False, 1, 3**9, "3", ""}; + for v in [alt1, alt2, alt3, set()]: + self.assertFalse(jref == v) + self.assertFalse(v == jref) + self.assertFalse(jref == self.type2test(v)) + self.assertFalse(self.type2test(v) == jref) + + # Test for http://bugs.jython.org/issue2639 + # This is to test the != comparisons between Java and Python sets + def test_inequality_empty_set(self): + js = self.type2test() + self.assertFalse(js != set()) + self.assertFalse(set() != js) + + def test_inequality_simple_set(self): + js = self.type2test() + self.assertTrue(js != set([1])) + self.assertTrue(set([1]) != js) + + def test_inequality_mixed_types_set(self): + ref = {False, 1, 3**9, "3"} + alt = {0, True, 3L**9, u"3"} + self.assertEqual(ref, alt) # test assumption + jref = self.type2test(ref) + + for v in [ref, alt, jref]: + self.assertFalse(jref != v) + self.assertFalse(v != jref) + self.assertFalse(jref != self.type2test(v)) + self.assertFalse(self.type2test(v) != jref) + + alt1 = {False, 1.01, 3**9, "3"} + alt2 = {False, 1, "3"}; + alt3 = {False, 1, 3**9, "3", ""}; + for v in [alt1, alt2, alt3, set()]: + self.assertTrue(jref != v) + self.assertTrue(v != jref) + self.assertTrue(jref != self.type2test(v)) + self.assertTrue(self.type2test(v) != jref) + class TestJavaHashSet(TestJavaSet): - thetype = HashSet + type2test = HashSet + class TestJavaLinkedHashSet(TestJavaSet): - thetype = LinkedHashSet + type2test = LinkedHashSet + class SetSubclassCallsSuperMethods(set): # Used to verify all call paths where there is more than one way # to call the super method, such as (union, __or__), etc - + def _valid_op_args(f): def _screener(*args): if len(args) != 2: @@ -132,12 +197,12 @@ def _mutating_convention(*args): def issubset(self, other): return super(SetSubclassCallsSuperMethods, self).issubset(other) - + __le__ = issubset def issuperset(self, other): return super(SetSubclassCallsSuperMethods, self).issuperset(other) - + __ge__ = issuperset def union(self, *others): @@ -166,7 +231,7 @@ def _update(self, *others): update = _call_for_side_effects(_update) __ior__ = _update - + def _difference_update(self, *others): super(SetSubclassCallsSuperMethods, self).difference_update(*others) return self diff --git a/Lib/test/test_shadowstr_jy.py b/Lib/test/test_shadowstr_jy.py new file mode 100644 index 000000000..e36e0cac5 --- /dev/null +++ b/Lib/test/test_shadowstr_jy.py @@ -0,0 +1,156 @@ +# Made for Jython + +# Tests of built-in type shadowstr + +import os +import sys +from test import string_tests +from test.test_support import run_unittest, is_jython +from test.test_str import StrTest +import unittest + +from org.python.core import PyShadowString + +# Ideally we would test shadowstr is a str but the tests need to sub-class it + +class StrTestCase( + string_tests.CommonTest, + string_tests.MixinStrUnicodeUserStringTest, + string_tests.MixinStrUserStringTest, + ): + # A PyShadowString should pass the tests for str too. + type2test = PyShadowString + + +class ShadowStrTestCase(unittest.TestCase): + + def setUp(self): + self.ss = PyShadowString("hello", "bonjour") + + # The Java class of a python module may be $py + CCLASS = r"test\.test_shadowstr_jy\$py" # compiled (e.g. regrtest) + # Or it may be org.python.pycode._pyx + PCLASS = r"org\.python\.pycode\._pyx\d+" # .py at the prompt + + def check_first_eq(self): + self.assertTrue(self.ss == "hello") + self.assertFalse(self.ss == "bonjour") + self.assertTrue("hello" == self.ss) + self.assertFalse("bonjour" == self.ss) + # shadowstring-shadowstring comparisons + tt = PyShadowString("hello", "goodbye") + self.assertTrue(self.ss == tt) # primary==primary + tt = PyShadowString("adieu", "hello") + self.assertFalse(self.ss == tt) # primary==shadow + self.assertFalse(tt == self.ss) # shadow==primary + tt = PyShadowString("adieu", "bonjour") + self.assertFalse(self.ss == tt) # shadow==shadow + + def check_both_eq(self): + self.assertTrue(self.ss == "hello") + self.assertTrue(self.ss == "bonjour") + self.assertTrue("hello" == self.ss) + self.assertTrue("bonjour" == self.ss) + # shadowstring-shadowstring comparisons + tt = PyShadowString("hello", "goodbye") + for c, m in self.ss.gettargets(): tt.addtarget(c, m) + self.assertTrue(self.ss == tt) # primary==primary + tt = PyShadowString("goodbye", "hello") + for c, m in self.ss.gettargets(): tt.addtarget(c, m) + self.assertTrue(self.ss == tt) # primary==shadow + self.assertTrue(tt == self.ss) # shadow==primary + tt = PyShadowString("adieu", "bonjour") + for c, m in self.ss.gettargets(): tt.addtarget(c, m) + self.assertTrue(self.ss == tt) # shadow==shadow + + def test_eq(self): + # Test recognition unconditionally + self.check_first_eq() + self.ss.addtarget(None) # match any + self.check_both_eq() + + def test_eq_class(self): + # Test recognition of class context only + self.check_first_eq() + self.ss.addtarget(self.CCLASS) + self.ss.addtarget(self.PCLASS) + self.check_both_eq() + + def test_eq_method(self): + # Test recognition of method context only + self.check_first_eq() + # The Java method name of a python function is name$ + self.ss.addtarget(None, r"test_eq_method\$\d+") # method only + self.check_both_eq() + + def test_eq_class_method(self): + # Test recognition of class and method context + self.check_first_eq() + # Match this method in this module + method = r"test_eq_class_method\$\d+" + self.ss.addtarget(self.CCLASS, method) + self.ss.addtarget(self.PCLASS, method) + self.check_both_eq() + + def check_first_startswith(self): + self.assertTrue(self.ss.startswith("hel")) + self.assertFalse(self.ss.startswith("bon")) + + def check_both_startswith(self): + self.assertTrue(self.ss.startswith("hel")) + self.assertTrue(self.ss.startswith("bon")) + + def test_startswith(self): + # Test recognition unconditionally + self.check_first_startswith() + self.ss.addtarget(None) # match any + self.check_both_startswith() + + def test_startswith_class(self): + # Test recognition of class context only + self.check_first_startswith() + self.ss.addtarget(self.CCLASS) # class only + self.ss.addtarget(self.PCLASS) # class only + self.check_both_startswith() + + def test_startswith_method(self): + # Test recognition of method context only + self.check_first_startswith() + self.ss.addtarget(None, r"test_startswith_method\$\d+") # method only + self.check_both_startswith() + + def test_startswith_class_method(self): + # Test recognition of class and method context + self.check_first_startswith() + # Match this method in this module + method = r"test_startswith_class_method\$\d+" + self.ss.addtarget(self.CCLASS, method) + self.ss.addtarget(self.PCLASS, method) + self.check_both_startswith() + + def test_slice(self): + # Test slicing goes through to the constituent strings consistently + def check(m, n): + tt = self.ss[m:n] + self.assertEqual(tt, "hello"[m:n]) + self.assertEqual(tt, "bonjour"[m:n]) + self.assertEqual(self.ss.gettargets(), tt.gettargets()) + + # Match this method in this module + method = r"test_slice\$\d+" + self.ss.addtarget(self.CCLASS, method) + self.ss.addtarget(self.PCLASS, method) + check(None, 3) + check(1, 5) + check(-3, None) + check(None, None) + +def test_main(): + run_unittest( + StrTestCase, + ShadowStrTestCase, + ) + + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_signal.py b/Lib/test/test_signal.py index 8805164f3..81967c075 100644 --- a/Lib/test/test_signal.py +++ b/Lib/test/test_signal.py @@ -22,9 +22,7 @@ if (sys.platform[:3] in ('win', 'os2') or sys.platform == 'riscos' or (test_support.is_jython and os._name == 'nt')): - raise test_support.TestSkipped("Can't test signal on %s" % \ - sys.platform) - + raise unittest.SkipTest("Can't test signal on %s" % sys.platform) class HandlerBCalled(Exception): pass @@ -208,6 +206,8 @@ def test_setting_signal_handler_to_none_raises_error(self): self.assertRaises(TypeError, signal.signal, signal.SIGUSR1, None) + @unittest.skipIf(test_support.is_jython, + "getsignal is equivalent but not identical (bjo #2790)") def test_getsignal(self): hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler) self.assertEquals(signal.getsignal(signal.SIGHUP), @@ -215,6 +215,13 @@ def test_getsignal(self): signal.signal(signal.SIGHUP, hup) self.assertEquals(signal.getsignal(signal.SIGHUP), hup) + def test_getsignal_jy(self): + hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler) + self.assertEquals(signal.getsignal(signal.SIGHUP), + self.trivial_signal_handler) + signal.signal(signal.SIGHUP, hup) + #self.assertEquals(signal.getsignal(signal.SIGHUP), hup) + class WakeupSignalTests(unittest.TestCase): TIMEOUT_FULL = 10 diff --git a/Lib/test/test_slots_jy.py b/Lib/test/test_slots_jy.py index e93d607fc..99bbff9c7 100644 --- a/Lib/test/test_slots_jy.py +++ b/Lib/test/test_slots_jy.py @@ -229,11 +229,53 @@ class B(object): self.assertIn("__weakref__", dir(self.make_class(HashMap, "__weakref__")())) +class MultiInheritanceSlotsTestCase(unittest.TestCase): + + def test_diamond_multi_inheritance_second_branch(self): + # see issue bugs.jython.org/issue2101 + # also related: bugs.jython.org/issue1996 + result = [] + + class A(object): + def method(self): + pass + + class B(A): + __slots__ = ('b') + def method(self): + result.append('B.method begin') + super(B, self).method() + self.b = 'b' + result.append('B.method end') + + class C(A): + def method(self): + result.append('C.method begin') + super(C, self).method() + self.c = 'c' + result.append('C.method end') + + class D1(B, C): + def method(self): super(D1, self).method() + + class D2(C, B): + def method(self): super(D2, self).method() + + D1().method() + self.assertEqual(result, + ['B.method begin', 'C.method begin', 'C.method end', 'B.method end']) + result = [] + D2().method() + self.assertEqual(result, + ['C.method begin', 'B.method begin', 'B.method end', 'C.method end']) + + def test_main(): test_support.run_unittest(SlottedTestCase, SlottedWithDictTestCase, SlottedWithWeakrefTestCase, - SpecialSlotsBaseTestCase) + SpecialSlotsBaseTestCase, + MultiInheritanceSlotsTestCase) if __name__ == '__main__': diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 414898e42..22cc63d80 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -31,6 +31,10 @@ import _socket _socket._NUM_THREADS = 5 + import java.util.logging + def _set_java_logging(name, level): + java.util.logging.Logger.getLogger(name).setLevel(level) + class SocketTCPTest(unittest.TestCase): @@ -2242,7 +2246,7 @@ def testUnresolvedAddress(self): try: self.s.connect( ('non.existent.server', PORT) ) except socket.gaierror, gaix: - self.failUnlessEqual(gaix[0], errno.EGETADDRINFOFAILED) + self.failUnlessEqual(gaix[0], errno.ENOEXEC) except Exception, x: self.fail("Get host name for non-existent host raised wrong exception: %s" % x) else: @@ -2620,6 +2624,16 @@ class MySocket(socket.socket): def test_main(): + + if test_support.is_jython: + # Netty logs stack dumps when we destroy sockets after their parent + # group, see http://bugs.jython.org/issue2517 . Is this a real bug? + # For now, treat as inconvenient artifact of test. + _set_java_logging("io.netty.channel.ChannelInitializer", + java.util.logging.Level.SEVERE) + _set_java_logging("io.netty.util.concurrent.DefaultPromise", + java.util.logging.Level.OFF) + tests = [ GeneralModuleTests, IPAddressTests, @@ -2672,5 +2686,6 @@ def test_main(): suites = [unittest.makeSuite(klass, 'test') for klass in tests] test_support._run_suite(unittest.TestSuite(suites)) + if __name__ == "__main__": test_main() diff --git a/Lib/test/test_socket_jy.py b/Lib/test/test_socket_jy.py index 0e5191388..6a57d4b7f 100644 --- a/Lib/test/test_socket_jy.py +++ b/Lib/test/test_socket_jy.py @@ -67,7 +67,7 @@ def do_workout(self, num_threads=10): target=self.do_nonblocking_connection, name="socket-workout-%s" % i, args=(connect_results, i))) - + for thread in connect_threads: thread.start() for thread in connect_threads: @@ -79,6 +79,7 @@ def test_connect_ex_workout(self): # Tests fix for http://bugs.jython.org/issue2428; based in part on the # code showing failure that was submitted with that bug for result in self.do_workout(): + if len(result) == 0: self.fail("A socket-workout thread failed to run") self.assertIn(result[0], {errno.EINPROGRESS, errno.EISCONN}) self.assertEqual(result[-1], errno.EISCONN) for code in result[1:-1]: @@ -124,25 +125,27 @@ def do_workout(self, num_threads=10): target=self.do_nonblocking_connection, name="socket-workout-%s" % i, args=(connect_results, i))) - + for thread in connect_threads: thread.start() for thread in connect_threads: thread.join() return connect_results + @unittest.skipIf(test_support.is_jython and test_support.get_java_version() >= (9,), # FIXME + "Fails on Java 9+. See b.j.o. issue #2710") def test_connect_ex_workout(self): """Verify connect_ex states go through EINPROGRESS?, EALREADY*, EISCONN""" # Tests fix for http://bugs.jython.org/issue2428; based in part on the # code showing failure that was submitted with that bug for result in self.do_workout(): + if len(result) == 0: self.fail("A socket-workout thread failed to run") self.assertIn(result[0], {errno.EINPROGRESS, errno.EISCONN}) self.assertEqual(result[-1], errno.EISCONN) for code in result[1:-1]: self.assertEqual(code, errno.EALREADY) - class SocketOptionsTest(unittest.TestCase): def test_socket_options_defined(self): diff --git a/Lib/test/test_sort.py b/Lib/test/test_sort.py index 7bff833a5..903229a17 100644 --- a/Lib/test/test_sort.py +++ b/Lib/test/test_sort.py @@ -43,6 +43,60 @@ def check(tag, expected, raw, compare=None): return class TestBase(unittest.TestCase): + + def testGently(self): + # + # This is a copy of testStressfully omitting the pathological comparator. See bjo #2812. + # + # Try a variety of sizes at and around powers of 2, and at powers of 10. + sizes = [0] + for power in range(1, 10): + n = 2 ** power + sizes.extend(range(n-1, n+2)) + sizes.extend([10, 100, 1000]) + + class Stable(object): + def __init__(self, key, i): + self.key = key + self.index = i + + def __cmp__(self, other): + return cmp(self.key, other.key) + __hash__ = None # Silence Py3k warning + + def __repr__(self): + return "Stable(%d, %d)" % (self.key, self.index) + + for n in sizes: + x = range(n) + if verbose: + print "Testing size", n + + s = x[:] + check("identity", x, s) + + s = x[:] + s.reverse() + check("reversed", x, s) + + s = x[:] + random.shuffle(s) + check("random permutation", x, s) + + y = x[:] + y.reverse() + s = x[:] + check("reversed via function", y, s, lambda a, b: cmp(b, a)) + + s = [Stable(random.randrange(10), i) for i in xrange(n)] + augmented = [(e, e.index) for e in s] + augmented.sort() # forced stable because ties broken by index + x = [e for e, i in augmented] # a stable sort of s + check("stability", x, s) + + + @unittest.skipIf(test_support.is_jython, + "Pathological comparators not handled. See bjo #2812.") def testStressfully(self): # Try a variety of sizes at and around powers of 2, and at powers of 10. sizes = [0] @@ -104,15 +158,8 @@ def __repr__(self): print " Checking against an insane comparison function." print " If the implementation isn't careful, this may segfault." s = x[:] - - if test_support.is_jython: - try: - s.sort(lambda a, b: int(random.random() * 3) - 1) - except java.lang.IllegalArgumentException: - pass - else: - s.sort(lambda a, b: int(random.random() * 3) - 1) - check("an insane function left some permutation", x, s) + s.sort(lambda a, b: int(random.random() * 3) - 1) + check("an insane function left some permutation", x, s) x = [Complains(i) for i in x] s = x[:] diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 126f794f7..cdcf85456 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -4,6 +4,7 @@ import sys import unittest from test import test_support as support +from test.script_helper import assert_python_ok import asyncore import socket import select @@ -13,11 +14,12 @@ import os import errno import pprint -import tempfile +import shutil import urllib2 import traceback import weakref import platform +import re import functools from contextlib import closing @@ -25,9 +27,18 @@ PROTOCOLS = sorted(ssl._PROTOCOL_NAMES) HOST = support.HOST +IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') +IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) + def data_file(*name): - return os.path.join(os.path.dirname(__file__), *name) + file = os.path.join(os.path.dirname(__file__), *name) + # Ensure we return unicode path. This tweak is not a divergence: + # CPython 2.7.13 fails the same way for a non-ascii location. + if isinstance(file, unicode): + return file + else: + return file.decode(sys.getfilesystemencoding()) # The custom key and certificate files used in test_ssl are generated # using Lib/test/make_ssl_certs.py. @@ -56,20 +67,30 @@ def data_file(*name): SIGNED_CERTFILE = data_file("keycert3.pem") SIGNED_CERTFILE2 = data_file("keycert4.pem") SIGNING_CA = data_file("pycacert.pem") +# cert with all kinds of subject alt names +ALLSANFILE = data_file("allsans.pem") REMOTE_HOST = "self-signed.pythontest.net" REMOTE_ROOT_CERT = data_file("selfsigned_pythontestdotnet.pem") EMPTYCERT = data_file("nullcert.pem") BADCERT = data_file("badcert.pem") -WRONGCERT = data_file("XXXnonexisting.pem") +NONEXISTINGCERT = data_file("XXXnonexisting.pem") BADKEY = data_file("badkey.pem") NOKIACERT = data_file("nokia.pem") NULLBYTECERT = data_file("nullbytecert.pem") +TALOS_INVALID_CRLDP = data_file("talos-2019-0758.pem") -DHFILE = data_file("dh1024.pem") +DHFILE = data_file("ffdh3072.pem") BYTES_DHFILE = DHFILE.encode(sys.getfilesystemencoding()) +# Not defined in all versions of OpenSSL +OP_NO_COMPRESSION = getattr(ssl, "OP_NO_COMPRESSION", 0) +OP_SINGLE_DH_USE = getattr(ssl, "OP_SINGLE_DH_USE", 0) +OP_SINGLE_ECDH_USE = getattr(ssl, "OP_SINGLE_ECDH_USE", 0) +OP_CIPHER_SERVER_PREFERENCE = getattr(ssl, "OP_CIPHER_SERVER_PREFERENCE", 0) +OP_ENABLE_MIDDLEBOX_COMPAT = getattr(ssl, "OP_ENABLE_MIDDLEBOX_COMPAT", 0) + def handle_error(prefix): exc_format = ' '.join(traceback.format_exception(*sys.exc_info())) @@ -145,6 +166,36 @@ def f(*args, **kwargs): else: return func +def skip_if_openssl_cnf_minprotocol_gt_tls1(func): + """Skip a test if the OpenSSL config MinProtocol is > TLSv1. + OS distros with an /etc/ssl/openssl.cnf and MinProtocol set often do so to + require TLSv1.2 or higher (Debian Buster). Some of our tests for older + protocol versions will fail under such a config. + Alternative workaround: Run this test in a process with + OPENSSL_CONF=/dev/null in the environment. + """ + @functools.wraps(func) + def f(*args, **kwargs): + openssl_cnf = os.environ.get("OPENSSL_CONF", "/etc/ssl/openssl.cnf") + try: + with open(openssl_cnf, "r") as config: + for line in config: + match = re.match(r"MinProtocol\s*=\s*(TLSv\d+\S*)", line) + if match: + tls_ver = match.group(1) + if tls_ver > "TLSv1": + raise unittest.SkipTest( + "%s has MinProtocol = %s which is > TLSv1." % + (openssl_cnf, tls_ver)) + except (EnvironmentError, UnicodeDecodeError) as err: + # no config file found, etc. + if support.verbose: + sys.stdout.write("\n Could not scan %s for MinProtocol: %s\n" + % (openssl_cnf, err)) + return func(*args, **kwargs) + return f + + needs_sni = unittest.skipUnless(ssl.HAS_SNI, "SNI support needed for this test") @@ -162,7 +213,13 @@ def test_constants(self): ssl.OP_NO_COMPRESSION self.assertIn(ssl.HAS_SNI, {True, False}) self.assertIn(ssl.HAS_ECDH, {True, False}) - + ssl.OP_NO_SSLv2 + ssl.OP_NO_SSLv3 + ssl.OP_NO_TLSv1 + # ssl.OP_NO_TLSv1_3 Not yet supported in Jython ssl.py + if ssl.OPENSSL_VERSION_INFO >= (1, 0, 1): + ssl.OP_NO_TLSv1_1 + ssl.OP_NO_TLSv1_2 def test_random(self): v = ssl.RAND_status() @@ -175,7 +232,6 @@ def test_random(self): self.assertRaises(TypeError, ssl.RAND_egd, 'foo', 1) ssl.RAND_add("this is a random string", 75.0) - @unittest.skipIf(support.is_jython, "Jython does not have _ssl, therefore this test needs to be rewritten") def test_parse_cert(self): # note that this uses an 'unofficial' function in _ssl.c, # provided solely for this test, to exercise the certificate @@ -190,9 +246,9 @@ def test_parse_cert(self): (('commonName', 'localhost'),)) ) # Note the next three asserts will fail if the keys are regenerated - self.assertEqual(p['notAfter'], asn1time('Oct 5 23:01:56 2020 GMT')) - self.assertEqual(p['notBefore'], asn1time('Oct 8 23:01:56 2010 GMT')) - self.assertEqual(p['serialNumber'], 'D7C7381919AFC24E') + self.assertEqual(p['notAfter'], asn1time('Aug 26 14:23:15 2028 GMT')) + self.assertEqual(p['notBefore'], asn1time('Aug 29 14:23:15 2018 GMT')) + self.assertEqual(p['serialNumber'], '98A7CF88C74A32ED') self.assertEqual(p['subject'], ((('countryName', 'XY'),), (('localityName', 'Castle Anthrax'),), @@ -216,7 +272,27 @@ def test_parse_cert(self): self.assertEqual(p['crlDistributionPoints'], ('http://SVRIntl-G3-crl.verisign.com/SVRIntlG3.crl',)) - @unittest.skipIf(support.is_jython, "Jython does not have _ssl, therefore this test needs to be rewritten") + def test_parse_cert_CVE_2019_5010(self): + p = ssl._ssl._test_decode_cert(TALOS_INVALID_CRLDP) + if support.verbose: + sys.stdout.write("\n" + pprint.pformat(p) + "\n") + self.assertEqual( + p, + { + 'issuer': ( + (('countryName', 'UK'),), (('commonName', 'cody-ca'),)), + 'notAfter': 'Jun 14 18:00:58 2028 GMT', + 'notBefore': 'Jun 18 18:00:58 2018 GMT', + 'serialNumber': '02', + 'subject': ((('countryName', 'UK'),), + (('commonName', + 'codenomicon-vm-2.test.lal.cisco.com'),)), + 'subjectAltName': ( + ('DNS', 'codenomicon-vm-2.test.lal.cisco.com'),), + 'version': 3 + } + ) + def test_parse_cert_CVE_2013_4238(self): p = ssl._ssl._test_decode_cert(NULLBYTECERT) if support.verbose: @@ -246,6 +322,27 @@ def test_parse_cert_CVE_2013_4238(self): self.assertEqual(p['subjectAltName'], san) + def test_parse_all_sans(self): + p = ssl._ssl._test_decode_cert(ALLSANFILE) + self.assertEqual(p['subjectAltName'], + ( + ('DNS', 'allsans'), + ('othername', ''), + ('othername', ''), + ('email', 'user@example.org'), + ('DNS', 'www.example.org'), + ('DirName', + ((('countryName', 'XY'),), + (('localityName', 'Castle Anthrax'),), + (('organizationName', 'Python Software Foundation'),), + (('commonName', 'dirname example'),))), + ('URI', 'https://www.python.org/'), + ('IP Address', '127.0.0.1'), + ('IP Address', '0:0:0:0:0:0:0:1\n'), + ('Registered ID', '1.2.3.4.5') + ) + ) + def test_DER_to_PEM(self): with open(CAFILE_CACERT, 'r') as f: pem = f.read() @@ -282,9 +379,9 @@ def test_openssl_version(self): self.assertGreaterEqual(status, 0) self.assertLessEqual(status, 15) # Version string as returned by {Open,Libre}SSL, the format might change - if "LibreSSL" in s: - self.assertTrue(s.startswith("LibreSSL {:d}.{:d}".format(major, minor)), - (s, t)) + if IS_LIBRESSL: + self.assertTrue(s.startswith("LibreSSL {:d}".format(major)), + (s, t, hex(n))) else: self.assertTrue(s.startswith("OpenSSL {:d}.{:d}.{:d}".format(major, minor, fix)), (s, t)) @@ -310,6 +407,7 @@ def test_wrapped_unconnected(self): self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1) self.assertRaises(socket.error, ss.send, b'x') self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0)) + self.assertRaises(NotImplementedError, ss.dup) def test_timeout(self): # Issue #8524: when creating an SSL socket, the timeout of the @@ -331,8 +429,8 @@ def test_errors(self): self.assertRaisesRegexp(ValueError, "certfile must be specified for server-side operations", ssl.wrap_socket, sock, server_side=True, certfile="") - if support.get_java_version() < (1, 9): - # Possible FIXME similar issue as seen in + if support.get_java_version() < (9,): + # FIXME: Fails on Java 9+. See b.j.o. issue #2710. A similar issue is seen in # test_load_cert_chain - apparently this RSA 1024 cert is too weak and gets a # java.security.KeyStoreException: Key protection algorithm not found before the # ValueError raised on earlier versions of Java; @@ -342,17 +440,42 @@ def test_errors(self): s.connect, (HOST, 8080)) with self.assertRaises(IOError) as cm: with closing(socket.socket()) as sock: - ssl.wrap_socket(sock, certfile=WRONGCERT) + ssl.wrap_socket(sock, certfile=NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) with self.assertRaises(IOError) as cm: with closing(socket.socket()) as sock: - ssl.wrap_socket(sock, certfile=CERTFILE, keyfile=WRONGCERT) + ssl.wrap_socket(sock, + certfile=CERTFILE, keyfile=NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) with self.assertRaises(IOError) as cm: with closing(socket.socket()) as sock: - ssl.wrap_socket(sock, certfile=WRONGCERT, keyfile=WRONGCERT) + ssl.wrap_socket(sock, + certfile=NONEXISTINGCERT, keyfile=NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) + def bad_cert_test(self, certfile): + """Check that trying to use the given client certificate fails""" + certfile = os.path.join(os.path.dirname(__file__) or os.curdir, + certfile) + sock = socket.socket() + self.addCleanup(sock.close) + with self.assertRaises(ssl.SSLError): + ssl.wrap_socket(sock, + certfile=certfile, + ssl_version=ssl.PROTOCOL_TLSv1) + + def test_empty_cert(self): + """Wrapping with an empty cert file""" + self.bad_cert_test("nullcert.pem") + + def test_malformed_cert(self): + """Wrapping with a badly formatted certificate (syntax error)""" + self.bad_cert_test("badcert.pem") + + def test_malformed_key(self): + """Wrapping with a badly formatted key (syntax error)""" + self.bad_cert_test("badkey.pem") + def test_match_hostname(self): def ok(cert, hostname): ssl.match_hostname(cert, hostname) @@ -577,32 +700,31 @@ def test_asn1object(self): self.assertIsInstance(val, ssl._ASN1Object) self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth') - # TODO Jython better asn1 support, though not sure there's much use for it - # val = ssl._ASN1Object.fromnid(129) - # self.assertEqual(val, expected) - # self.assertIsInstance(val, ssl._ASN1Object) - # self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1) - # with self.assertRaisesRegexp(ValueError, "unknown NID 100000"): - # ssl._ASN1Object.fromnid(100000) - # for i in range(1000): - # try: - # obj = ssl._ASN1Object.fromnid(i) - # except ValueError: - # pass - # else: - # self.assertIsInstance(obj.nid, int) - # self.assertIsInstance(obj.shortname, str) - # self.assertIsInstance(obj.longname, str) - # self.assertIsInstance(obj.oid, (str, type(None))) - # - # val = ssl._ASN1Object.fromname('TLS Web Server Authentication') - # self.assertEqual(val, expected) - # self.assertIsInstance(val, ssl._ASN1Object) - # self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected) - # self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'), - # expected) - # with self.assertRaisesRegexp(ValueError, "unknown object 'serverauth'"): - # ssl._ASN1Object.fromname('serverauth') + val = ssl._ASN1Object.fromnid(129) + self.assertEqual(val, expected) + self.assertIsInstance(val, ssl._ASN1Object) + self.assertRaises(ValueError, ssl._ASN1Object.fromnid, -1) + with self.assertRaisesRegexp(ValueError, "unknown NID 100000"): + ssl._ASN1Object.fromnid(100000) + for i in range(1000): + try: + obj = ssl._ASN1Object.fromnid(i) + except ValueError: + pass + else: + self.assertIsInstance(obj.nid, int) + self.assertIsInstance(obj.shortname, str) + self.assertIsInstance(obj.longname, str) + self.assertIsInstance(obj.oid, (str, type(None))) + + val = ssl._ASN1Object.fromname('TLS Web Server Authentication') + self.assertEqual(val, expected) + self.assertIsInstance(val, ssl._ASN1Object) + self.assertEqual(ssl._ASN1Object.fromname('serverAuth'), expected) + self.assertEqual(ssl._ASN1Object.fromname('1.3.6.1.5.5.7.3.1'), + expected) + with self.assertRaisesRegexp(ValueError, "unknown object 'serverauth'"): + ssl._ASN1Object.fromname('serverauth') def test_purpose_enum(self): val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') @@ -714,7 +836,6 @@ def test_protocol(self): ctx = ssl.SSLContext(proto) self.assertEqual(ctx.protocol, proto) - @unittest.skipIf(support.is_jython, "Currently not supported") def test_ciphers(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.set_ciphers("ALL") @@ -726,17 +847,20 @@ def test_ciphers(self): def test_options(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, - ctx.options) + default = (ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3) + # SSLContext also enables these by default + default |= (OP_NO_COMPRESSION | OP_CIPHER_SERVER_PREFERENCE | + OP_SINGLE_DH_USE | OP_SINGLE_ECDH_USE | + OP_ENABLE_MIDDLEBOX_COMPAT) + self.assertEqual(default, ctx.options) ctx.options |= ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1, - ctx.options) + self.assertEqual(default | ssl.OP_NO_TLSv1, ctx.options) if can_clear_options(): - ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 - self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, - ctx.options) + ctx.options = (ctx.options & ~ssl.OP_NO_TLSv1) + self.assertEqual(default, ctx.options) ctx.options = 0 - self.assertEqual(0, ctx.options) + # Ubuntu has OP_NO_SSLv3 forced on by default + self.assertEqual(0, ctx.options & ~ssl.OP_NO_SSLv3) else: with self.assertRaises(ValueError): ctx.options = 0 @@ -776,20 +900,22 @@ def test_verify_flags(self): with self.assertRaises(TypeError): ctx.verify_flags = None + @unittest.skipIf(support.is_jython and support.get_java_version() < (1,8), + "Fails on Java 7. See bjo #2770") def test_load_cert_chain(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) # Combined key and cert in a single file ctx.load_cert_chain(CERTFILE, keyfile=None) - if support.get_java_version() < (1, 9): - # Possible FIXME we may be skipping this test on Java 9 unnecessarily. - # CERTFILE as generated uses RSA 1024, which is considered too weak. + if support.get_java_version() < (9,): + # FIXME: Fails on Java 9+. See b.j.o. issue #2710. A similar issue is seen in + # test_errors. CERTFILE as generated uses RSA 1024, which is considered too weak. # This may be why this raises an error on Java 9: # java.security.KeyStoreException: Key protection algorithm not found: # java.security.KeyStoreException: Certificate chain is not valid ctx.load_cert_chain(CERTFILE, keyfile=CERTFILE) self.assertRaises(TypeError, ctx.load_cert_chain, keyfile=CERTFILE) with self.assertRaises(IOError) as cm: - ctx.load_cert_chain(WRONGCERT) + ctx.load_cert_chain(NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(BADCERT) @@ -875,7 +1001,7 @@ def test_load_verify_locations(self): self.assertRaises(TypeError, ctx.load_verify_locations) self.assertRaises(TypeError, ctx.load_verify_locations, None, None, None) with self.assertRaises(IOError) as cm: - ctx.load_verify_locations(WRONGCERT) + ctx.load_verify_locations(NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) with self.assertRaises(IOError): ctx.load_verify_locations(u'') @@ -945,8 +1071,14 @@ def test_load_verify_cadata(self): ctx.load_verify_locations(cadata=b"broken") - @unittest.skipIf(support.is_jython, "Not yet supported on Jython") def test_load_dh_params(self): + filename = u'dhpäräm.pem' + fs_encoding = sys.getfilesystemencoding() + try: + filename.encode(fs_encoding) + except UnicodeEncodeError: + self.skipTest("filename %r cannot be encoded to the filesystem encoding %r" % (filename, fs_encoding)) + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.load_dh_params(DHFILE) if os.name != 'nt': @@ -954,10 +1086,14 @@ def test_load_dh_params(self): self.assertRaises(TypeError, ctx.load_dh_params) self.assertRaises(TypeError, ctx.load_dh_params, None) with self.assertRaises(IOError) as cm: - ctx.load_dh_params(WRONGCERT) + ctx.load_dh_params(NONEXISTINGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) with self.assertRaises(ssl.SSLError) as cm: ctx.load_dh_params(CERTFILE) + with support.temp_dir() as d: + fname = os.path.join(d, filename) + shutil.copy(DHFILE, fname) + ctx.load_dh_params(fname) @skip_if_broken_ubuntu_ssl def test_session_stats(self): @@ -1025,16 +1161,13 @@ def test_cert_store_stats(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.cert_store_stats(), {'x509_ca': 0, 'crl': 0, 'x509': 0}) - - # Jython x509 will grow by 1 while openssl remains 0 - # TODO investgate deeper ctx.load_cert_chain(CERTFILE) self.assertEqual(ctx.cert_store_stats(), - {'x509_ca': 0, 'crl': 0, 'x509': 1}) + {'x509_ca': 0, 'crl': 0, 'x509': 0}) ctx.load_verify_locations(CERTFILE) self.assertEqual(ctx.cert_store_stats(), - {'x509_ca': 0, 'crl': 0, 'x509': 2}) - ctx.load_verify_locations(REMOTE_ROOT_CERT) + {'x509_ca': 0, 'crl': 0, 'x509': 1}) + ctx.load_verify_locations(CAFILE_CACERT) self.assertEqual(ctx.cert_store_stats(), {'x509_ca': 1, 'crl': 0, 'x509': 2}) @@ -1064,11 +1197,12 @@ def test_get_ca_certs(self): # # see this sample code on how we might be able to decode: # https://svn.apache.org/repos/asf/cxf/tags/cxf-2.4.4/distribution/src/main/release/samples/sts_issue_operation/src/main/java/demo/sts/provider/cert/CRLVerifier.java + # Subject and issuer ordering also differs vs CPython 2.7 latest with open(CAFILE_CACERT) as f: pem = f.read() - der = ssl.PEM_cert_to_DER_cert(pem) - self.assertEqual(ctx.get_ca_certs(True), [der]) + der = ssl.PEM_cert_to_DER_cert(pem) + self.assertEqual(ctx.get_ca_certs(True), [der]) def test_load_default_certs(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) @@ -1086,13 +1220,14 @@ def test_load_default_certs(self): self.assertRaises(TypeError, ctx.load_default_certs, 'SERVER_AUTH') @unittest.skipIf(sys.platform == "win32", "not-Windows specific") + @unittest.skipIf(IS_LIBRESSL, "LibreSSL doesn't support env vars") def test_load_default_certs_env(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) with support.EnvironmentVarGuard() as env: env["SSL_CERT_DIR"] = CAPATH env["SSL_CERT_FILE"] = CERTFILE ctx.load_default_certs() - self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 4, "x509_ca": 0}) + self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 1, "x509_ca": 0}) @unittest.skipUnless(sys.platform == "win32", "Windows specific") def test_load_default_certs_env_windows(self): @@ -1108,16 +1243,29 @@ def test_load_default_certs_env_windows(self): stats["x509"] += 1 self.assertEqual(ctx.cert_store_stats(), stats) + def _assert_context_options(self, ctx): + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + if OP_NO_COMPRESSION != 0: + self.assertEqual(ctx.options & OP_NO_COMPRESSION, + OP_NO_COMPRESSION) + if OP_SINGLE_DH_USE != 0: + self.assertEqual(ctx.options & OP_SINGLE_DH_USE, + OP_SINGLE_DH_USE) + if OP_SINGLE_ECDH_USE != 0: + self.assertEqual(ctx.options & OP_SINGLE_ECDH_USE, + OP_SINGLE_ECDH_USE) + if OP_CIPHER_SERVER_PREFERENCE != 0: + self.assertEqual(ctx.options & OP_CIPHER_SERVER_PREFERENCE, + OP_CIPHER_SERVER_PREFERENCE) + def test_create_default_context(self): ctx = ssl.create_default_context() + self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) self.assertTrue(ctx.check_hostname) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) - # self.assertEqual( - # ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), - # getattr(ssl, "OP_NO_COMPRESSION", 0), - # ) + self._assert_context_options(ctx) + with open(SIGNING_CA) as f: cadata = f.read().decode("ascii") @@ -1125,40 +1273,24 @@ def test_create_default_context(self): cadata=cadata) self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) - # self.assertEqual( - # ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), - # getattr(ssl, "OP_NO_COMPRESSION", 0), - # ) + self._assert_context_options(ctx) ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) - # self.assertEqual( - # ctx.options & getattr(ssl, "OP_NO_COMPRESSION", 0), - # getattr(ssl, "OP_NO_COMPRESSION", 0), - # ) - # self.assertEqual( - # ctx.options & getattr(ssl, "OP_SINGLE_DH_USE", 0), - # getattr(ssl, "OP_SINGLE_DH_USE", 0), - # ) - # self.assertEqual( - # ctx.options & getattr(ssl, "OP_SINGLE_ECDH_USE", 0), - # getattr(ssl, "OP_SINGLE_ECDH_USE", 0), - # ) + self._assert_context_options(ctx) def test__create_stdlib_context(self): ctx = ssl._create_stdlib_context() self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) self.assertFalse(ctx.check_hostname) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + self._assert_context_options(ctx) ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + self._assert_context_options(ctx) ctx = ssl._create_stdlib_context(ssl.PROTOCOL_TLSv1, cert_reqs=ssl.CERT_REQUIRED, @@ -1166,12 +1298,63 @@ def test__create_stdlib_context(self): self.assertEqual(ctx.protocol, ssl.PROTOCOL_TLSv1) self.assertEqual(ctx.verify_mode, ssl.CERT_REQUIRED) self.assertTrue(ctx.check_hostname) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + self._assert_context_options(ctx) ctx = ssl._create_stdlib_context(purpose=ssl.Purpose.CLIENT_AUTH) self.assertEqual(ctx.protocol, ssl.PROTOCOL_SSLv23) self.assertEqual(ctx.verify_mode, ssl.CERT_NONE) - self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + self._assert_context_options(ctx) + + def test__https_verify_certificates(self): + # Unit test to check the contect factory mapping + # The factories themselves are tested above + # This test will fail by design if run under PYTHONHTTPSVERIFY=0 + # (as will various test_httplib tests) + + # Uses a fresh SSL module to avoid affecting the real one + local_ssl = support.import_fresh_module("ssl") + # Certificate verification is enabled by default + self.assertIs(local_ssl._create_default_https_context, + local_ssl.create_default_context) + # Turn default verification off + local_ssl._https_verify_certificates(enable=False) + self.assertIs(local_ssl._create_default_https_context, + local_ssl._create_unverified_context) + # And back on + local_ssl._https_verify_certificates(enable=True) + self.assertIs(local_ssl._create_default_https_context, + local_ssl.create_default_context) + # The default behaviour is to enable + local_ssl._https_verify_certificates(enable=False) + local_ssl._https_verify_certificates() + self.assertIs(local_ssl._create_default_https_context, + local_ssl.create_default_context) + + def test__https_verify_envvar(self): + # Unit test to check the PYTHONHTTPSVERIFY handling + # Need to use a subprocess so it can still be run under -E + https_is_verified = """import ssl, sys; \ + status = "Error: _create_default_https_context does not verify certs" \ + if ssl._create_default_https_context is \ + ssl._create_unverified_context \ + else None; \ + sys.exit(status)""" + https_is_not_verified = """import ssl, sys; \ + status = "Error: _create_default_https_context verifies certs" \ + if ssl._create_default_https_context is \ + ssl.create_default_context \ + else None; \ + sys.exit(status)""" + extra_env = {} + # Omitting it leaves verification on + assert_python_ok("-c", https_is_verified, **extra_env) + # Setting it to zero turns verification off + extra_env[ssl._https_verify_envvar] = "0" + assert_python_ok("-c", https_is_not_verified, **extra_env) + # Any other value should also leave it on + for setting in ("", "1", "enabled", "foo"): + extra_env[ssl._https_verify_envvar] = setting + assert_python_ok("-c", https_is_verified, **extra_env) def test_check_hostname(self): ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) @@ -1201,14 +1384,13 @@ class SSLErrorTests(unittest.TestCase): def test_str(self): # The str() of a SSLError doesn't include the errno e = ssl.SSLError(1, "foo") - self.assertIn("foo", str(e)) + self.assertEqual(str(e), "foo") self.assertEqual(e.errno, 1) # Same for a subclass e = ssl.SSLZeroReturnError(1, "foo") - self.assertIn("foo", str(e)) + self.assertEqual(str(e), "foo") self.assertEqual(e.errno, 1) - @unittest.skipIf(support.is_jython, "TODO") def test_lib_reason(self): # Test the library and reason attributes ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) @@ -1219,7 +1401,6 @@ def test_lib_reason(self): s = str(cm.exception) self.assertTrue(s.startswith("[PEM: NO_START_LINE] no start line"), s) - @unittest.skipIf(support.is_jython, "TODO") def test_subclass(self): # Check that the appropriate SSLError subclass is raised # (this only tests one of them) @@ -1275,7 +1456,7 @@ def test_connect_ex(self): cert_reqs=ssl.CERT_REQUIRED, ca_certs=REMOTE_ROOT_CERT) try: - self.assertEqual(errno.EISCONN, s.connect_ex((REMOTE_HOST, 443))) + self.assertEqual(0, s.connect_ex((REMOTE_HOST, 443))) self.assertTrue(s.getpeercert()) finally: s.close() @@ -1292,8 +1473,7 @@ def test_non_blocking_connect_ex(self): s.setblocking(False) rc = s.connect_ex((REMOTE_HOST, 443)) # EWOULDBLOCK under Windows, EINPROGRESS elsewhere - # Jython added EALREADY, as in Jython connect may have already happened - self.assertIn(rc, (0, errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK)) + self.assertIn(rc, (0, errno.EINPROGRESS, errno.EWOULDBLOCK)) # Wait for connect to finish select.select([], [s], [], 5.0) # Non-blocking handshake @@ -1306,7 +1486,7 @@ def test_non_blocking_connect_ex(self): except ssl.SSLWantWriteError: select.select([], [s], [], 5.0) # SSL established - #self.assertTrue(s.getpeercert()) + self.assertTrue(s.getpeercert()) finally: s.close() @@ -1321,9 +1501,9 @@ def test_timeout_connect_ex(self): try: s.settimeout(0.0000001) rc = s.connect_ex((REMOTE_HOST, 443)) - if rc == errno.EISCONN: + if rc == 0: self.skipTest("REMOTE_HOST responded too quickly") - self.assertIn(rc, (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK)) + self.assertIn(rc, (errno.EAGAIN, errno.EWOULDBLOCK)) finally: s.close() @@ -1426,7 +1606,6 @@ def test_connect_cadata(self): cert = s.getpeercert() self.assertTrue(cert) - @unittest.skipIf(support.is_jython, "Can't use a socket as a file under Jython") @unittest.skipIf(os.name == "nt", "Can't use a socket as a file under Windows") def test_makefile_close(self): # Issue #5238: creating a file-like object with makefile() shouldn't @@ -1485,7 +1664,6 @@ def _test_get_server_certificate(host, port, cert=None): sys.stdout.write("%s\n" % x) else: self.fail("Got server certificate %s for %s:%s!" % (pem, host, port)) - pem = ssl.get_server_certificate((host, port), ca_certs=cert) if not pem: @@ -1497,7 +1675,6 @@ def _test_get_server_certificate(host, port, cert=None): if support.IPV6_ENABLED: _test_get_server_certificate('ipv6.google.com', 443) - @unittest.skipIf(support.is_jython, "Currently not supported") def test_ciphers(self): remote = (REMOTE_HOST, 443) with support.transient_internet(remote[0]): @@ -1514,35 +1691,6 @@ def test_ciphers(self): cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") s.connect(remote) - def test_algorithms(self): - # Issue #8484: all algorithms should be available when verifying a - # certificate. - # SHA256 was added in OpenSSL 0.9.8 - if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): - self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) - # sha256.tbs-internet.com needs SNI to use the correct certificate - if not ssl.HAS_SNI: - self.skipTest("SNI needed for this test") - # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) - remote = ("sha256.tbs-internet.com", 443) - sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") - with support.transient_internet("sha256.tbs-internet.com"): - ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) - ctx.verify_mode = ssl.CERT_REQUIRED - ctx.load_verify_locations(sha256_cert) - s = ctx.wrap_socket(socket.socket(socket.AF_INET), - server_hostname="sha256.tbs-internet.com") - try: - s.connect(remote) - if support.verbose: - sys.stdout.write("\nCipher with %r is %r\n" % - (remote, s.cipher())) - sys.stdout.write("Certificate is:\n%s\n" % - pprint.pformat(s.getpeercert())) - finally: - s.close() - - @unittest.skipIf(support.is_jython, "On jython preloaded TODO") def test_get_ca_certs_capath(self): # capath certs are loaded on request with support.transient_internet(REMOTE_HOST): @@ -1557,7 +1705,7 @@ def test_get_ca_certs_capath(self): self.assertTrue(cert) finally: s.close() - self.assertEqual(len(ctx.get_ca_certs()), 3) + self.assertEqual(len(ctx.get_ca_certs()), 1) @needs_sni def test_context_setget(self): @@ -1578,9 +1726,7 @@ def test_context_setget(self): import threading except ImportError: _have_threads = False - -_have_threads = False -if _have_threads: # Jython skip threading tests for now, really don't work :( +else: _have_threads = True from test.ssl_servers import make_https_server @@ -1609,23 +1755,43 @@ def wrap_conn(self): self.sock, server_side=True) self.server.selected_npn_protocols.append(self.sslconn.selected_npn_protocol()) self.server.selected_alpn_protocols.append(self.sslconn.selected_alpn_protocol()) - except socket.error as e: - # We treat ConnectionResetError as though it were an - # SSLError - OpenSSL on Ubuntu abruptly closes the - # connection when asked to use an unsupported protocol. - # - # XXX Various errors can have happened here, for example - # a mismatching protocol version, an invalid certificate, - # or a low-level bug. This should be made more discriminating. - if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET: - raise - self.server.conn_errors.append(e) - if self.server.chatty: - handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") - self.running = False - self.server.stop() - self.close() - return False + except (ssl.SSLError, socket.error, OSError) as e: + if e.errno in (errno.ECONNRESET, errno.EPIPE, errno.ESHUTDOWN): + # Mimick Python 3: + # + # except (ConnectionResetError, BrokenPipeError): + # + # We treat ConnectionResetError as though it were an + # SSLError - OpenSSL on Ubuntu abruptly closes the + # connection when asked to use an unsupported protocol. + # + # BrokenPipeError is raised in TLS 1.3 mode, when OpenSSL + # tries to send session tickets after handshake. + # https://github.com/openssl/openssl/issues/6342 + self.server.conn_errors.append(str(e)) + if self.server.chatty: + handle_error( + "\n server: bad connection attempt from " + + repr(self.addr) + ":\n") + self.running = False + self.close() + return False + else: + # OSError may occur with wrong protocols, e.g. both + # sides use PROTOCOL_TLS_SERVER. + # + # XXX Various errors can have happened here, for example + # a mismatching protocol version, an invalid certificate, + # or a low-level bug. This should be made more discriminating. + if not isinstance(e, ssl.SSLError) and e.errno != errno.ECONNRESET: + raise + self.server.conn_errors.append(e) + if self.server.chatty: + handle_error("\n server: bad connection attempt from " + repr(self.addr) + ":\n") + self.running = False + self.server.stop() + self.close() + return False else: if self.server.context.verify_mode == ssl.CERT_REQUIRED: cert = self.sslconn.getpeercert() @@ -1724,7 +1890,7 @@ def __init__(self, certificate=None, ssl_version=None, else: self.context = ssl.SSLContext(ssl_version if ssl_version is not None - else ssl.PROTOCOL_TLSv1) + else ssl.PROTOCOL_TLS) self.context.verify_mode = (certreqs if certreqs is not None else ssl.CERT_NONE) if cacerts: @@ -1884,6 +2050,8 @@ def __exit__(self, *args): self.join() if support.verbose: sys.stdout.write(" cleanup: successfully joined.\n") + # make sure that ConnectionHandler is removed from socket_map + asyncore.close_all(ignore_all=True) def start(self, flag=None): self.flag = flag @@ -1903,36 +2071,6 @@ def stop(self): self.active = False self.server.close() - def bad_cert_test(certfile): - """ - Launch a server with CERT_REQUIRED, and check that trying to - connect to it with the given client certificate fails. - """ - server = ThreadedEchoServer(CERTFILE, - certreqs=ssl.CERT_REQUIRED, - cacerts=CERTFILE, chatty=False, - connectionchatty=False) - with server: - try: - with closing(socket.socket()) as sock: - s = ssl.wrap_socket(sock, - certfile=certfile, - ssl_version=ssl.PROTOCOL_TLSv1) - s.connect((HOST, server.port)) - except ssl.SSLError as x: - if support.verbose: - sys.stdout.write("\nSSLError is %s\n" % x.args[1]) - except OSError as x: - if support.verbose: - sys.stdout.write("\nOSError is %s\n" % x.args[1]) - except OSError as x: - if x.errno != errno.ENOENT: - raise - if support.verbose: - sys.stdout.write("\OSError is %s\n" % str(x)) - else: - raise AssertionError("Use of invalid cert should have failed!") - def server_params_test(client_context, server_context, indata=b"FOO\n", chatty=True, connectionchatty=False, sni_name=None): """ @@ -2171,22 +2309,38 @@ def test_check_hostname(self): "check_hostname requires server_hostname"): context.wrap_socket(s) - def test_empty_cert(self): - """Connecting with an empty cert file""" - bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, - "nullcert.pem")) - def test_malformed_cert(self): - """Connecting with a badly formatted certificate (syntax error)""" - bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, - "badcert.pem")) - def test_nonexisting_cert(self): - """Connecting with a non-existing cert file""" - bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, - "wrongcert.pem")) - def test_malformed_key(self): - """Connecting with a badly formatted key (syntax error)""" - bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir, - "badkey.pem")) + def test_wrong_cert(self): + """Connecting when the server rejects the client's certificate + + Launch a server with CERT_REQUIRED, and check that trying to + connect to it with a wrong client certificate fails. + """ + certfile = os.path.join(os.path.dirname(__file__) or os.curdir, + "keycert.pem") + server = ThreadedEchoServer(SIGNED_CERTFILE, + certreqs=ssl.CERT_REQUIRED, + cacerts=SIGNING_CA, chatty=False, + connectionchatty=False) + with server, \ + closing(socket.socket()) as sock, \ + closing(ssl.wrap_socket(sock, + certfile=certfile, + ssl_version=ssl.PROTOCOL_TLSv1)) as s: + try: + # Expect either an SSL error about the server rejecting + # the connection, or a low-level connection reset (which + # sometimes happens on Windows) + s.connect((HOST, server.port)) + except ssl.SSLError as e: + if support.verbose: + sys.stdout.write("\nSSLError is %r\n" % e) + except socket.error as e: + if e.errno != errno.ECONNRESET: + raise + if support.verbose: + sys.stdout.write("\nsocket.error is %r\n" % e) + else: + self.fail("Use of invalid cert should have failed!") def test_rude_shutdown(self): """A brutal shutdown of an SSL server should raise an OSError @@ -2253,6 +2407,7 @@ def test_protocol_sslv2(self): client_options=ssl.OP_NO_TLSv1) @skip_if_broken_ubuntu_ssl + @skip_if_openssl_cnf_minprotocol_gt_tls1 def test_protocol_sslv23(self): """Connecting to an SSLv23 server with various client options""" if support.verbose: @@ -2330,6 +2485,7 @@ def test_protocol_tlsv1(self): @skip_if_broken_ubuntu_ssl @unittest.skipUnless(hasattr(ssl, "PROTOCOL_TLSv1_1"), "TLS version 1.1 not supported.") + @skip_if_openssl_cnf_minprotocol_gt_tls1 def test_protocol_tlsv1_1(self): """Connecting to a TLSv1.1 server with various client options. Testing against older TLS versions.""" @@ -2458,8 +2614,6 @@ def test_socketserver(self): def test_asyncore_server(self): """Check the example asyncore integration.""" - indata = "TEST MESSAGE of mixed case\n" - if support.verbose: sys.stdout.write("\n") @@ -2591,9 +2745,41 @@ def _recvfrom_into(): # consume data s.read() + # read(-1, buffer) is supported, even though read(-1) is not + data = b"data" + s.send(data) + buffer = bytearray(len(data)) + self.assertEqual(s.read(-1, buffer), len(data)) + self.assertEqual(buffer, data) + + self.assertRaises(NotImplementedError, s.dup) s.write(b"over\n") + + self.assertRaises(ValueError, s.recv, -1) + self.assertRaises(ValueError, s.read, -1) + s.close() + def test_recv_zero(self): + server = ThreadedEchoServer(CERTFILE) + server.__enter__() + self.addCleanup(server.__exit__, None, None) + s = socket.create_connection((HOST, server.port)) + self.addCleanup(s.close) + s = ssl.wrap_socket(s, suppress_ragged_eofs=False) + self.addCleanup(s.close) + + # recv/read(0) should return no data + s.send(b"data") + self.assertEqual(s.recv(0), b"") + self.assertEqual(s.read(0), b"") + self.assertEqual(s.read(), b"data") + + # Should not block if the other end sends no data + s.setblocking(False) + self.assertEqual(s.recv(0), b"") + self.assertEqual(s.recv_into(bytearray()), 0) + def test_handshake_timeout(self): # Issue #5103: SSL handshake must respect the socket timeout server = socket.socket(socket.AF_INET) @@ -2663,7 +2849,7 @@ def serve(): # Block on the accept and wait on the connection to close. evt.set() remote[0], peer[0] = server.accept() - remote[0].recv(1) + remote[0].send(remote[0].recv(4)) t = threading.Thread(target=serve) t.start() @@ -2671,6 +2857,8 @@ def serve(): evt.wait() client = context.wrap_socket(socket.socket()) client.connect((host, port)) + client.send(b'data') + client.recv() client_addr = client.getsockname() client.close() t.join() @@ -2694,19 +2882,24 @@ def test_do_handshake_enotconn(self): sock.do_handshake() self.assertEqual(cm.exception.errno, errno.ENOTCONN) - def test_default_ciphers(self): - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - try: - # Force a set of weak ciphers on our client context - context.set_ciphers("DES") - except ssl.SSLError: - self.skipTest("no DES cipher available") - with ThreadedEchoServer(CERTFILE, - ssl_version=ssl.PROTOCOL_SSLv23, - chatty=False) as server: - with closing(context.wrap_socket(socket.socket())) as s: - with self.assertRaises(ssl.SSLError): - s.connect((HOST, server.port)) + def test_no_shared_ciphers(self): + server_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + server_context.load_cert_chain(SIGNED_CERTFILE) + client_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + client_context.verify_mode = ssl.CERT_REQUIRED + client_context.check_hostname = True + + # OpenSSL enables all TLS 1.3 ciphers, enforce TLS 1.2 for test + client_context.options |= ssl.OP_NO_TLSv1_3 + # Force different suites on client and master + client_context.set_ciphers("AES128") + server_context.set_ciphers("AES256") + with ThreadedEchoServer(context=server_context) as server: + s = client_context.wrap_socket( + socket.socket(), + server_hostname="localhost") + with self.assertRaises(ssl.SSLError): + s.connect((HOST, server.port)) self.assertIn("no shared cipher", str(server.conn_errors[0])) def test_version_basic(self): @@ -2721,15 +2914,37 @@ def test_version_basic(self): with closing(context.wrap_socket(socket.socket())) as s: self.assertIs(s.version(), None) s.connect((HOST, server.port)) - self.assertEqual(s.version(), "TLSv1") + self.assertEqual(s.version(), 'TLSv1') self.assertIs(s.version(), None) + @unittest.skipUnless(ssl.HAS_TLSv1_3, + "test requires TLSv1.3 enabled OpenSSL") + def test_tls1_3(self): + context = ssl.SSLContext(ssl.PROTOCOL_TLS) + context.load_cert_chain(CERTFILE) + # disable all but TLS 1.3 + context.options |= ( + ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2 + ) + with ThreadedEchoServer(context=context) as server: + s = context.wrap_socket(socket.socket()) + with closing(s): + s.connect((HOST, server.port)) + self.assertIn(s.cipher()[0], [ + 'TLS_AES_256_GCM_SHA384', + 'TLS_CHACHA20_POLY1305_SHA256', + 'TLS_AES_128_GCM_SHA256', + ]) + @unittest.skipUnless(ssl.HAS_ECDH, "test requires ECDH-enabled OpenSSL") def test_default_ecdh_curve(self): # Issue #21015: elliptic curve-based Diffie Hellman key exchange # should be enabled by default on SSL contexts. context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) context.load_cert_chain(CERTFILE) + # TLSv1.3 defaults to PFS key agreement and no longer has KEA in + # cipher name. + context.options |= ssl.OP_NO_TLSv1_3 # Prior to OpenSSL 1.0.0, ECDH ciphers have to be enabled # explicitly using the 'ECCdraft' cipher alias. Otherwise, # our default cipher list should prefer ECDH-based ciphers @@ -2863,24 +3078,37 @@ def test_alpn_protocols(self): (['http/3.0', 'http/4.0'], None) ] for client_protocols, expected in protocol_tests: - server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) server_context.load_cert_chain(CERTFILE) server_context.set_alpn_protocols(server_protocols) - client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2) client_context.load_cert_chain(CERTFILE) client_context.set_alpn_protocols(client_protocols) - stats = server_params_test(client_context, server_context, - chatty=True, connectionchatty=True) - msg = "failed trying %s (s) and %s (c).\n" \ - "was expecting %s, but got %%s from the %%s" \ - % (str(server_protocols), str(client_protocols), - str(expected)) - client_result = stats['client_alpn_protocol'] - self.assertEqual(client_result, expected, msg % (client_result, "client")) - server_result = stats['server_alpn_protocols'][-1] \ - if len(stats['server_alpn_protocols']) else 'nothing' - self.assertEqual(server_result, expected, msg % (server_result, "server")) + try: + stats = server_params_test(client_context, + server_context, + chatty=True, + connectionchatty=True) + except ssl.SSLError as e: + stats = e + + if (expected is None and IS_OPENSSL_1_1 + and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)): + # OpenSSL 1.1.0 to 1.1.0e raises handshake error + self.assertIsInstance(stats, ssl.SSLError) + else: + msg = "failed trying %s (s) and %s (c).\n" \ + "was expecting %s, but got %%s from the %%s" \ + % (str(server_protocols), str(client_protocols), + str(expected)) + client_result = stats['client_alpn_protocol'] + self.assertEqual(client_result, expected, + msg % (client_result, "client")) + server_result = stats['server_alpn_protocols'][-1] \ + if len(stats['server_alpn_protocols']) else 'nothing' + self.assertEqual(server_result, expected, + msg % (server_result, "server")) def test_selected_npn_protocol(self): # selected_npn_protocol() is None unless NPN is used @@ -3038,8 +3266,9 @@ def test_read_write_after_close_raises_valuerror(self): self.assertRaises(ValueError, s.write, b'hello') -def test_main(verbose=False): - if support.verbose: + +def test_main(verbose=False,tests=[]): + if verbose or support.verbose: plats = { 'Linux': platform.linux_distribution, 'Mac': platform.mac_ver, @@ -3070,20 +3299,22 @@ def test_main(verbose=False): if not os.path.exists(filename): raise support.TestFailed("Can't read certificate file %r" % filename) - tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] - - if support.is_resource_enabled('network'): - tests.append(NetworkedTests) + used_threads = False + if not tests: + tests = [ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] + if support.is_resource_enabled('network'): + tests.append(NetworkedTests) - if _have_threads: - thread_info = support.threading_setup() - if thread_info: - tests.append(ThreadedTests) + if _have_threads: + used_threads = True + thread_info = support.threading_setup() + if thread_info: + tests.append(ThreadedTests) try: support.run_unittest(*tests) finally: - if _have_threads: + if used_threads: support.threading_cleanup(*thread_info) if __name__ == "__main__": diff --git a/Lib/test/test_ssl_jy.py b/Lib/test/test_ssl_jy.py new file mode 100644 index 000000000..959230a72 --- /dev/null +++ b/Lib/test/test_ssl_jy.py @@ -0,0 +1,231 @@ +# Jython variations on the test_ssl tests are concentrated here, where possible +# Due to the structure of the module, some functions still have to be modified +# directly in the original, but this reduces the diff and ongoing merge effort + +import errno +import select +import socket +import ssl +import sys +import unittest +import test.test_ssl +from test.test_ssl import BasicTests +from test.test_ssl import can_clear_options, support, skip_if_broken_ubuntu_ssl +from test.test_ssl import CAPATH, CERTFILE, CAFILE_CACERT +from test.test_ssl import REMOTE_HOST, REMOTE_ROOT_CERT + + + +class BasicSocketTests(test.test_ssl.BasicSocketTests): + @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten") + def test_parse_cert(self): + None + + @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten") + def test_parse_cert_CVE_2013_4238(self): + None + + @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten") + def test_parse_cert_CVE_2019_5010(self): + None + + @unittest.skip("Jython does not have _ssl, therefore this test needs to be rewritten") + def test_parse_all_sans(self): + None + + def test_asn1object(self): + # Abbreviated version of parent test up to unsupported part + # TODO Jython better asn1 support, though not sure there's much use for + # it + expected = (129, 'serverAuth', 'TLS Web Server Authentication', + '1.3.6.1.5.5.7.3.1') + + val = ssl._ASN1Object('1.3.6.1.5.5.7.3.1') + self.assertEqual(val, expected) + self.assertEqual(val.nid, 129) + self.assertEqual(val.shortname, 'serverAuth') + self.assertEqual(val.longname, 'TLS Web Server Authentication') + self.assertEqual(val.oid, '1.3.6.1.5.5.7.3.1') + self.assertIsInstance(val, ssl._ASN1Object) + self.assertRaises(ValueError, ssl._ASN1Object, 'serverAuth') + + +class ContextTests(test.test_ssl.ContextTests): + @unittest.skip("Currently not supported") + def test_ciphers(self): + None + + @skip_if_broken_ubuntu_ssl + def test_options(self): + # new default options in later 2.7 versions not yet supported + # See CPython b8eaec697a2b5d9d2def2950a0aa50e8ffcf1059 + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + # OP_ALL | OP_NO_SSLv2 | OP_NO_SSLv3 is the default value + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3, + ctx.options) + ctx.options |= ssl.OP_NO_TLSv1 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1, + ctx.options) + if can_clear_options(): + ctx.options = (ctx.options & ~ssl.OP_NO_SSLv2) | ssl.OP_NO_TLSv1 + self.assertEqual(ssl.OP_ALL | ssl.OP_NO_TLSv1 | ssl.OP_NO_SSLv3, + ctx.options) + ctx.options = 0 + self.assertEqual(0, ctx.options) + else: + with self.assertRaises(ValueError): + ctx.options = 0 + + @unittest.skip("Not yet supported on Jython") + def test_load_dh_params(self): + None + + def test_cert_store_stats(self): + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + self.assertEqual(ctx.cert_store_stats(), + {'x509_ca': 0, 'crl': 0, 'x509': 0}) + # Jython x509 will grow by 1 while openssl remains 0 + # TODO investgate deeper + ctx.load_cert_chain(CERTFILE) + self.assertEqual(ctx.cert_store_stats(), + {'x509_ca': 0, 'crl': 0, 'x509': 1}) + ctx.load_verify_locations(CERTFILE) + self.assertEqual(ctx.cert_store_stats(), + {'x509_ca': 0, 'crl': 0, 'x509': 2}) + ctx.load_verify_locations(CAFILE_CACERT) + self.assertEqual(ctx.cert_store_stats(), + {'x509_ca': 1, 'crl': 0, 'x509': 2}) + + @unittest.skipIf(sys.platform == "win32", "not-Windows specific") + def test_load_default_certs_env(self): + # Store behaviour differs from CPython so different stats + ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) + with support.EnvironmentVarGuard() as env: + env["SSL_CERT_DIR"] = CAPATH + env["SSL_CERT_FILE"] = CERTFILE + ctx.load_default_certs() + self.assertEqual(ctx.cert_store_stats(), {"crl": 0, "x509": 5, "x509_ca": 0}) + + def _assert_context_options(self, ctx): + self.assertEqual(ctx.options & ssl.OP_NO_SSLv2, ssl.OP_NO_SSLv2) + # Jython doesn't support OP_NO_COMPRESSION, OP_SINGLE_DH_USE + # OP_SINGLE_ECDH_USE, OP_CIPHER_SERVER_PREFERENCE + + @unittest.skip("Jython not using ssl.__https_verify_certificates ") + def test__https_verify_certificates(self): + None + + @unittest.skip("Jython not using ssl._https_verify_envvar ") + def test__https_verify_envvar(self): + None + + +class SSLErrorTests(test.test_ssl.SSLErrorTests): + def test_str(self): + # Different error strings for Jython + # The str() of a SSLError doesn't include the errno + e = ssl.SSLError(1, "foo") + self.assertIn("foo", str(e)) + self.assertEqual(e.errno, 1) + # Same for a subclass + e = ssl.SSLZeroReturnError(1, "foo") + self.assertIn("foo", str(e)) + self.assertEqual(e.errno, 1) + + @unittest.skip("Jython TODO") + def test_lib_reason(self): + None + + @unittest.skip("Jython TODO") + def test_subclass(self): + None + + +class NetworkedTests(test.test_ssl.NetworkedTests): + def test_connect_ex(self): + # Issue #11326: check connect_ex() implementation + with support.transient_internet(REMOTE_HOST): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=REMOTE_ROOT_CERT) + try: + # Jython, errno.EISCONN expected per earlier 2.x versions, not 0 + self.assertEqual(errno.EISCONN, s.connect_ex((REMOTE_HOST, 443))) + self.assertTrue(s.getpeercert()) + finally: + s.close() + + def test_non_blocking_connect_ex(self): + # Issue #11326: non-blocking connect_ex() should allow handshake + # to proceed after the socket gets ready. + # Jython behaviour varies + with support.transient_internet(REMOTE_HOST): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=REMOTE_ROOT_CERT, + do_handshake_on_connect=False) + try: + s.setblocking(False) + rc = s.connect_ex((REMOTE_HOST, 443)) + # EWOULDBLOCK under Windows, EINPROGRESS elsewhere + # Jython added EALREADY, as in Jython connect may have already happened + self.assertIn(rc, (0, errno.EINPROGRESS, errno.EALREADY, errno.EWOULDBLOCK)) + # Wait for connect to finish + select.select([], [s], [], 5.0) + # Non-blocking handshake + while True: + try: + s.do_handshake() + break + except ssl.SSLWantReadError: + select.select([s], [], [], 5.0) + except ssl.SSLWantWriteError: + select.select([], [s], [], 5.0) + # SSL established - not in Jython + #self.assertTrue(s.getpeercert()) + finally: + s.close() + + def test_timeout_connect_ex(self): + # Issue #12065: on a timeout, connect_ex() should return the original + # errno (mimicking the behaviour of non-SSL sockets). + # Jython follows earlier 2.x behaviour of errno.EISCONN + # it also allows errno.TIMEDOUT + with support.transient_internet(REMOTE_HOST): + s = ssl.wrap_socket(socket.socket(socket.AF_INET), + cert_reqs=ssl.CERT_REQUIRED, + ca_certs=REMOTE_ROOT_CERT, + do_handshake_on_connect=False) + try: + s.settimeout(0.0000001) + rc = s.connect_ex((REMOTE_HOST, 443)) + if rc == errno.EISCONN: + self.skipTest("REMOTE_HOST responded too quickly") + self.assertIn(rc, (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK)) + finally: + s.close() + + @unittest.skip("Can't use a socket as a file under Jython") + def test_makefile_close(self): + None + + @unittest.skip("Currently not supported") + def test_ciphers(self): + None + + @unittest.skip("On jython preloaded TODO") + def test_get_ca_certs_capath(self): + None + + +def test_main(verbose=False): + tests=[ContextTests, BasicTests, BasicSocketTests, SSLErrorTests] + if support.is_resource_enabled('network'): + tests.append(NetworkedTests) + # Jython skip threading tests for now, really don't work :( + test.test_ssl.test_main(verbose, tests) + + +if __name__ == "__main__": + test_main() + diff --git a/Lib/test/test_strptime_jy.py b/Lib/test/test_strptime_jy.py index 0c0d0ef2a..f785a34fc 100644 --- a/Lib/test/test_strptime_jy.py +++ b/Lib/test/test_strptime_jy.py @@ -1,8 +1,14 @@ -# merge into upstream test_strptime.py at some point +# Java locale differences from JDK 9 onwards, and locale variation on +# developer machines, break test_strptime tests. This manifests more on Windows. +# Rather than diverge from the Python source, this overrides with extra locale +# setup. +# Merging back into CPython is desirable, but is a bigger discussion around +# library merging generally. import unittest from datetime import datetime from time import strptime +from test.test_strptime import * from test import test_support @@ -26,11 +32,23 @@ def test_issue2112(self): d = strptime('1', '%d') self.assertEqual(1900, d.tm_year) -def test_main(): + +def test_main(initialize=True): + test_support.force_reset_locale(initialize) + test_support.run_unittest( + getlang_Tests, + LocaleTime_Tests, + TimeRETests, + StrptimeTests, + Strptime12AMPMTests, + JulianTests, + CalculationTests, + CacheTests, ParsingTests ) if __name__ == '__main__': - test_main() + test_main(initialize=False) + diff --git a/Lib/test/test_struct_jy.py b/Lib/test/test_struct_jy.py new file mode 100644 index 000000000..745cfa853 --- /dev/null +++ b/Lib/test/test_struct_jy.py @@ -0,0 +1,158 @@ +import unittest +from test import test_support +import struct + +import sys +ISBIGENDIAN = sys.byteorder == "big" + +class StructTests(unittest.TestCase): # (format, argument, big-endian result, little-endian result, asymmetric) + _tests = [ + ('c', 'a', 'a', 'a', 0), + ('xc', 'a', '\0a', '\0a', 0), + ('cx', 'a', 'a\0', 'a\0', 0), + ('s', 'a', 'a', 'a', 0), + ('0s', 'helloworld', '', '', 1), + ('1s', 'helloworld', 'h', 'h', 1), + ('9s', 'helloworld', 'helloworl', 'helloworl', 1), + ('10s', 'helloworld', 'helloworld', 'helloworld', 0), + ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1), + ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1), + ('b', 7, '\7', '\7', 0), + ('b', -7, '\371', '\371', 0), + ('B', 7, '\7', '\7', 0), + ('B', 249, '\371', '\371', 0), + ('h', 700, '\002\274', '\274\002', 0), + ('h', -700, '\375D', 'D\375', 0), + ('H', 700, '\002\274', '\274\002', 0), + ('H', 0x10000-700, '\375D', 'D\375', 0), + ('i', 70000000, '\004,\035\200', '\200\035,\004', 0), + ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0), + ('I', 70000000L, '\004,\035\200', '\200\035,\004', 0), + ('I', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), + ('l', 70000000, '\004,\035\200', '\200\035,\004', 0), + ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0), + ('L', 70000000L, '\004,\035\200', '\200\035,\004', 0), + ('L', 0x100000000L-70000000, '\373\323\342\200', '\200\342\323\373', 0), + ('f', 2.0, '@\000\000\000', '\000\000\000@', 0), + ('d', 2.0, '@\000\000\000\000\000\000\000', + '\000\000\000\000\000\000\000@', 0), + ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), + ('d', -2.0, '\300\000\000\000\000\000\000\000', + '\000\000\000\000\000\000\000\300', 0), + ] + + def test_struct(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack(xfmt, res)[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + + def test_struct_unpack_bytearray(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack(xfmt, bytearray(res))[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + + def test_struct_unpack_buffer(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack(xfmt, buffer(res))[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + def test_struct_unpack_from(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack_from(xfmt, res)[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + + def test_struct_unpack_from_bytearray(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack_from(xfmt, bytearray(res))[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + + def test_struct_unpack_from_buffer(self): + for fmt, arg, big, lil, asy in self._tests: + for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), + ('='+fmt, ISBIGENDIAN and big or lil)]: + res = struct.pack(xfmt, arg) + self.assertEqual(res,exp,msg="pack(%r, %r) -> %r # expected %r" % + (fmt, arg, res, exp)) + n=struct.calcsize(xfmt) + self.assertEqual(n, len(res),msg="calcsize(%r) -> %d # expected %d" % + (xfmt, n, len(res))) + rev = struct.unpack_from(xfmt, buffer(res))[0] + if asy: + self.assertNotEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, exp)) + else: + self.assertEqual(arg,rev,msg="unpack(%r, %r) -> (%r,) # expected (%r,)" % + (fmt, res, rev, arg)) + + + + +def test_main(): + test_support.run_unittest(__name__) + +if __name__ == "__main__": + test_main() diff --git a/Lib/test/test_support.py b/Lib/test/test_support.py index f79f50316..1803c0354 100644 --- a/Lib/test/test_support.py +++ b/Lib/test/test_support.py @@ -55,9 +55,27 @@ is_jython_posix = is_jython and (os._name == 'posix') if is_jython: - def get_java_version(): - # returns (1, 9) for Java 9, etc - return tuple((int(x) for x in platform.java_ver()[0].split('.')[0:2])) + def get_java_version(version=None): + """return a tuple of int encoding the Java version (as in java.version). + + "1.8.0_121" -> (1, 8, 0, 121) + "9.0.4" -> (9, 0, 4) + "11" -> (11,) + "12-ea" -> (12,) + This parses strings (java.version properties) that conform to: + http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html + and http://openjdk.java.net/jeps/223 (but doesn't validate them). + """ + if version is None: + version = platform.java_ver()[0] + version = version.split('-')[0] # discard optional pre-release indicator + parts = version.split('_') # pre-JEP-223 format like 1.8.0_121 + parts[0:1] = parts[0].split('.') + try: + return tuple(int(x) for x in parts) + except: + return () + class Error(Exception): """Base class for regression test exceptions.""" @@ -477,11 +495,16 @@ def u(s): return unicode(s, 'unicode-escape') if is_jython: - def make_jar_classloader(jar): + def make_jar_classloader(jar, parent=False): import os from java.net import URL, URLClassLoader + from java.io import File + + if isinstance(jar, bytes): # Java will expect a unicode file name + jar = jar.decode(sys.getfilesystemencoding()) + jar_url = File(jar).toURI().toURL().toString() + url = URL(u'jar:%s!/' % jar_url) - url = URL('jar:file:%s!/' % jar) if is_jython_nt: # URLJarFiles keep a cached open file handle to the jar even # after this ClassLoader is GC'ed, disallowing Windows tests @@ -493,13 +516,16 @@ def make_jar_classloader(jar): # better fix conn.setDefaultUseCaches(False) - return URLClassLoader([url]) + if parent is False: + return URLClassLoader([url]) + else: + return URLClassLoader([url], parent) # Filename used for testing if is_jython: # Jython disallows @ in module names TESTFN = '$test' - TESTFN_UNICODE = "$test-\xe0\xf2" + TESTFN_UNICODE = u"$test-\u87d2\u86c7" # = test python (Chinese) TESTFN_ENCODING = sys.getfilesystemencoding() elif os.name == 'riscos': TESTFN = 'testfile' @@ -565,6 +591,10 @@ def make_jar_classloader(jar): # module name. TESTFN = "{}_{}_tmp".format(TESTFN, "1") #XXX "1" is a dummy for os.getpid() +# Define the URL of a dedicated HTTP server for the network tests. +# The URL must use clear-text HTTP: no redirection to encrypted HTTPS. +TEST_HTTP_URL = "http://www.pythontest.net" + # Save the initial cwd SAVEDCWD = os.getcwd() @@ -1098,6 +1128,35 @@ def inner(*args, **kwds): return inner return decorator +#======================================================================= +# Reset locale to C / POSIX locale. In Jython to date the default locale +# has been Locale.getDefaultLocale(), ie OS determined +# The new locale.setlocale() support is in beta and off by default, +# but some tests need the changes it introduces to pass. +# It requires certain "startup" initialization corresponding to +# -J-Dpython.locale.control=settable which is hard to simulate in a unit +# test. To see the calling test pass without the reload throat-clearing, +# invoke Jython with python.locale.control=settable on the command line, +# in either direct or regrtest flavours. +# Use of this function can be removed from most tests once +# locale.setlocale() support is on by default +def force_reset_locale(initialize=True): + import locale + if initialize: + from datetime import datetime + import time + from java.lang import System + System.setProperty('python.locale.control','settable') + import _locale + reload(_locale) + reload(locale) + # Trigger date format cache reload - need lang change + import _strptime + locale.setlocale(locale.LC_ALL,'de_DE') + _strptime._strptime('16', '%d') # numbers more portable hopefully + locale.setlocale(locale.LC_ALL,'C') + + #======================================================================= # Big-memory-test support. Separate from 'resources' because memory use should be configurable. diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index c038a9f0c..e59143edd 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -253,8 +253,6 @@ def test_attributes(self): self.assert_(vi[3] in ("alpha", "beta", "candidate", "final")) self.assert_(isinstance(vi[4], int)) - @unittest.skipIf(test.test_support.is_jython_nt, - "FIXME: fails probably due to issue 2312") def test_ioencoding(self): # from v2.7 test import subprocess,os env = dict(os.environ) diff --git a/Lib/test/test_time.py b/Lib/test/test_time.py index 8e2a8a9fa..cddc816fd 100644 --- a/Lib/test/test_time.py +++ b/Lib/test/test_time.py @@ -1,4 +1,7 @@ +# A version of the CPython stdlib test/test_time.py modified for Jython +# from test import test_support +import os import time import unittest @@ -238,6 +241,27 @@ def test_gmtime_tmetuple(self): t = time.gmtime() self.assertEqual(tuple(t), t) + EXAMPLES = { + 1526823094 : (2018, 5, 20, 13, 31, 34, 6, 140, 0), # recently + 1442224245.0 : (2015, 9, 14, 9, 50, 45, 0, 257, 0), # gravity + 768232800 : (1994, 5, 6, 14, 0, 0, 4, 126, 0), # tunnel + } + + if os.name=='posix' or os.name=='java': + # Times before 1970 are supported. + EXAMPLES.update({ + -14182940.0 : (1969, 7, 20, 20, 17, 40, 6, 201, 0), # moon + -6857222400 : (1752, 9, 14, 0, 0, 0, 3, 258, 0), # Gregorian (UK/US) + -6857222400 - 1 : (1752, 9, 13, 23, 59, 59, 2, 257, 0), + -12219292800 : (1582, 10, 15, 0, 0, 0, 4, 288, 0), # Gregorian (first adopters) + -12219292800 - 1 : (1582, 10, 14, 23, 59, 59, 3, 287, 0), + }) + + def test_gmtime_examples(self): + for seconds, ref in TimeTestCase.EXAMPLES.iteritems(): + t = time.gmtime(seconds) + self.assertEqual(tuple(t), ref) + def test_localtime_without_arg(self): lt0 = time.localtime() lt1 = time.localtime(None) diff --git a/Lib/test/test_unicode_jy.py b/Lib/test/test_unicode_jy.py index 212bd918b..fd44e504c 100644 --- a/Lib/test/test_unicode_jy.py +++ b/Lib/test/test_unicode_jy.py @@ -122,8 +122,8 @@ def test_join(self): self.assertRaises(UnicodeDecodeError, '毛泽东'.join, [u'foo', u'bar']) def test_file_encoding(self): - '''Ensure file writing doesn't attempt to encode things by default and reading doesn't - decode things by default. This was jython's behavior prior to 2.2.1''' + # Ensure file writing doesn't attempt to encode things by default and reading doesn't + # decode things by default. This was jython's behavior prior to 2.2.1''' EURO_SIGN = u"\u20ac" try: EURO_SIGN.encode() @@ -852,8 +852,9 @@ def check_unused_args(self, used_args, args, kwargs): self.assertRaises(ValueError, fmt.format, u"{0}", 10, 20, i=100) self.assertRaises(ValueError, fmt.format, u"{i}", 10, 20, i=100) + class UnicodeSpaceTest(unittest.TestCase): - # Test classification of characters as whitespace (some Jython divergence) + # Test classification of characters as whitespace (strictly as observed in CPython) def checkequal(self, expected, obj, methodname, *args): "check that object.method() returns expected result" @@ -862,15 +863,10 @@ def checkequal(self, expected, obj, methodname, *args): self.assertEqual(expected, realresult, grumble) # print grumble, 'x' if realresult != expected else '.' - # The set of Unicode characters that are spaces according to CPython 2.7.8 - SPACE = u'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f\x20\x85\xa0\u1680\u180e' + \ - u'\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a' + \ + # The set of Unicode characters that are spaces according to CPython 2.7.15 + SPACE = u'\t\n\x0b\x0c\r\x1c\x1d\x1e\x1f\x20\x85\xa0\u1680\u180e' \ + u'\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a' \ u'\u2028\u2029\u202f\u205f\u3000' - if test_support.is_jython: - # Not whitespace in Jython based on java.lang.Character.isWhitespace. - # This test documents the divergence, until we decide to remove it. - for c in u'\x85\xa0\u2007\u202f': - SPACE = SPACE.replace(c, u'') def test_isspace(self): for c in self.SPACE: @@ -901,8 +897,449 @@ def test_split(self): self.assertEqual(2, len(s.rsplit()), "no rsplit made in " + repr(s)) +class EncodingContext(object): + """Context manager to save and restore the encoding. + + Use like this: + + with EncodingContext("utf-8"): + self.assertEqual("'caf\xc3\xa9'", u"'caf\xe9'") + """ + + def __init__(self, encoding): + if not hasattr(sys, "setdefaultencoding"): + reload(sys) + self.original_encoding = sys.getdefaultencoding() + sys.setdefaultencoding(encoding) + + def __enter__(self): + return self + + def __exit__(self, *ignore_exc): + sys.setdefaultencoding(self.original_encoding) + + +class DefaultDecodingTestCase(unittest.TestCase): + # Test use of default encoding to coerce byte-like data to unicode + + BYTE_TYPES = (str, buffer, bytearray, memoryview) + BYTE_TYPES_COMPARE = (str, buffer) # Restricted as for CPython __eq__ etc. + + if not test_support.is_jython: + # CPython restricts the acceptable the byte-like types by context + BYTE_TYPES = (str, buffer) + BYTE_TYPES_COMPARE = (str, buffer) + + # Operators + + def test_add(self): + cs = self.encoding + ref = u'café crème' + s1 = ref[:4].encode(cs) + s2 = ref[4:].encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + b2 = B(s2) + self.assertEqual( ref[:4] + b2, ref) + # Really we're testing that str promotes. Other Bs may not. + self.assertEqual( s1 + ref[4:], ref) + + def test_in(self): + cs = self.encoding + ref = u'café crème' + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertTrue(B(u'é'.encode(cs)) in ref) + self.assertTrue(B(u'fé'.encode(cs)) in ref) + # Fails if the string is interpreted as code points. + if cs != 'latin-1': + self.assertFalse(B('\xc3\xa9') in u'caf\xc3\xa9') + + def test_eq(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive a string such that u1 != u and the encoded versions s, s1 + u1 = u.replace('cr', 'm') + s, s1 = u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b, b1 = B(s), B(s1) + self.assertTrue (u == b ) + self.assertTrue (b == u ) + self.assertFalse(u == b1) + self.assertFalse(b1== u ) + # Check not implicitly comparing as latin-1. + if cs != 'latin-1': + b = B('caf\xc3\xa9') + self.assertFalse(u'caf\xc3\xa9'== b) + self.assertFalse(b == u'caf\xc3\xa9') + + def test_ne(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive a string such that u1 != u and the encoded versions s, s1 + u1 = u.replace('cr', 'm') + s, s1 = u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b, b1 = B(s), B(s1) + self.assertTrue (u != b1) + self.assertTrue (b != u1) + self.assertFalse(u != b ) + self.assertFalse(b != u ) + # Check not implicitly comparing as latin-1. + if cs != 'latin-1': + b = B('caf\xc3\xa9') + self.assertTrue(u'caf\xc3\xa9'!= b) + self.assertTrue(b != u'caf\xc3\xa9') + + def test_lt(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive strings such that u0 < u < u1 and their encodings + u0 = u.replace('cr', 'Cr') + u1 = u.replace('.', '?') + s0, s, s1 = u0.encode(cs), u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b0, b, b1 = B(s0), B(s), B(s1) + self.assertTrue (b0 < u ) + self.assertFalse(b < u ) + self.assertFalse(b1 < u ) + self.assertFalse(u < b0) + self.assertFalse(u < b ) + self.assertTrue (u < b1) + + def test_le(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive strings such that u0 < u < u1 and their encodings + u0 = u.replace('cr', 'Cr') + u1 = u.replace('.', '?') + s0, s, s1 = u0.encode(cs), u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b0, b, b1 = B(s0), B(s), B(s1) + self.assertTrue (b0 <= u ) + self.assertTrue (b <= u ) + self.assertFalse(b1 <= u ) + self.assertFalse(u <= b0) + self.assertTrue (u <= b ) + self.assertTrue (u <= b1) + + def test_gt(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive strings such that u0 < u < u1 and their encodings + u0 = u.replace('cr', 'Cr') + u1 = u.replace('.', '?') + s0, s, s1 = u0.encode(cs), u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b0, b, b1 = B(s0), B(s), B(s1) + self.assertTrue (b1 > u ) + self.assertFalse(b > u ) + self.assertFalse(b0 > u ) + self.assertFalse(u > b1) + self.assertFalse(u > b ) + self.assertTrue (u > b0) + + def test_ge(self): + cs = self.encoding + u = u"Un caf\xe9 cr\xe8me." + # Derive strings such that u0 < u < u1 and their encodings + u0 = u.replace('cr', 'Cr') + u1 = u.replace('.', '?') + s0, s, s1 = u0.encode(cs), u.encode(cs), u1.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES_COMPARE: + #print B, + b0, b, b1 = B(s0), B(s), B(s1) + self.assertTrue (b1 >= u ) + self.assertTrue (b >= u ) + self.assertFalse(b0 >= u ) + self.assertFalse(u >= b1) + self.assertTrue (u >= b ) + self.assertTrue (u >= b0) + + + # Methods + + def test_count(self): + cs = self.encoding + ref = u'Le café des fées égarées' + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.count(B(u'é'.encode(cs))), 4) + self.assertEqual(ref.count(B(u'fé'.encode(cs))), 2) + + def test_endswith(self): + cs = self.encoding + # Set up the test using unicode values and indices + ref = u'café crème' + s, u, v = ref[-4:], u'èm£', u'èµe' + # Encode all this + enc = ref.encode(cs) + s1, u1, v1 = s.encode(cs), u.encode(cs), v.encode(cs) + + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + sb, ub, vb = B(s1), B(u1), B(v1) + # Test with single argument + self.assertFalse(ref.endswith(vb)) + self.assertTrue(ref.endswith(sb)) + # Test with a mixed tuple as the argument + self.assertFalse(ref.endswith((ub, u, vb, v))) + self.assertTrue(ref.endswith((ub, sb, vb))) + self.assertTrue(ref.endswith((ub, u, sb, vb, v))) + self.assertFalse(enc.endswith((ub, vb, u, v))) + self.assertTrue(enc.endswith((u, s, v))) + self.assertTrue(enc.endswith((ub, u, s, vb, v))) + + def test_endswith_slice(self): + cs = self.encoding + # Set up the test using unicode values and indices + ref = u'«Un café crème?»' + if len(u'«»'.encode(cs))!=2 and not test_support.is_jython: + # CPython fails on str.startswith(unicode, int, int) as it passes + # byte indices to unicode.startswith(unicode, int, int) unchanged. + # It only works if « and » encode to single bytes. Easier test: + ref = u'"Un café crème?"' + a, b = 4, -2 + s, u, v = ref[b-4:b], u'èm£', u'èµe' + # Encode all this, including the indices + enc = ref.encode(cs) + u1, v1 = u.encode(cs), v.encode(cs) + a1 = len(ref[:a].encode(cs)) + b1 = - len(ref[b:].encode(cs)) + s1 = s.encode(cs) + + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + sb, ub, vb = B(s1), B(u1), B(v1) + # Test the assumption on which the test is based + self.assertEqual(ref[a:b], enc[a1:b1]) + # Test slice with single argument + self.assertFalse(ref.endswith(vb, a, b)) + self.assertTrue(ref.endswith(sb, a, b)) + self.assertFalse(enc.endswith(vb, a1, b1)) + self.assertTrue(enc.endswith(s, a1, b1)) + # CPython would pass: + #self.assertTrue(enc.endswith(s, a, b)) + # Test slice with a mixed tuple as the argument + self.assertFalse(ref.endswith((ub, u, vb, v), a, b)) + self.assertTrue(ref.endswith((ub, sb, vb), a, b)) + self.assertTrue(ref.endswith((ub, u, sb, vb, v), a, b)) + self.assertFalse(enc.endswith((ub, vb, u, v), a1, b1)) + self.assertTrue(enc.endswith((u, s, v), a1, b1)) + self.assertTrue(enc.endswith((ub, u, s, vb, v), a1, b1)) + # CPython would pass: + #self.assertTrue(enc.endswith((u, s, v), a, b)) + #self.assertTrue(enc.endswith((ub, u, s, vb, v), a, b)) + + def test_find(self): + cs = self.encoding + ref = u'café crème' + sub = u'è'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.find(B(sub)), 7) + + def test_index(self): + cs = self.encoding + ref = u'café crème' + sub = u'è'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.index(B(sub)), 7) + + def test_lstrip(self): + cs = self.encoding + ref = u"¤£¥¥£¤du blé £" + sep = u'¥£¤'.encode(cs) + with EncodingContext(cs): + self.assertEqual(ref.lstrip(sep), u"du blé £") + + def test_partition(self): + cs = self.encoding + ref = u"Des fées hébétées." + sep1 = u'é'.encode(cs) + sep2 = u'ées'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.partition(B(sep1)), (u"Des f", u"é", u"es hébétées.")) + self.assertEqual(ref.partition(B(sep2)), (u"Des f", u"ées", u" hébétées.")) + + def test_replace(self): + cs = self.encoding + ref = u"Été." + a = u'É'.encode(cs) + b = u'é'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.replace(B(a), B(b)), u"été.") + self.assertEqual(ref.replace(B(b), B(a)), u"ÉtÉ.") + + def test_rfind(self): + cs = self.encoding + ref = u'café crème' + sub = u'é'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.rfind(B(sub)), 3) + + def test_rindex(self): + cs = self.encoding + ref = u'café crème' + sub = u'é'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.index(B(sub)), 3) + + def test_rpartition(self): + cs = self.encoding + ref = u"Des fées hébétées." + sep1 = u'é'.encode(cs) + sep2 = u'ées'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.rpartition(B(sep1)), (u"Des fées hébét", u"é", u"es.")) + self.assertEqual(ref.rpartition(B(sep2)), (u"Des fées hébét", u"ées", u".")) + + def test_rsplit(self): + cs = self.encoding + ref = u"Des fées hébétées." + sep1 = u'é'.encode(cs) + sep2 = u'ées'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.rsplit(B(sep1), 3), [u"Des fées h", u"b", u"t", u"es."]) + self.assertEqual(ref.rsplit(B(sep2)), [u"Des f", u" hébét", u"."]) + + def test_rstrip(self): + cs = self.encoding + ref = u"£ du bl饣¤¤£¥" + sep = u'¥£¤'.encode(cs) + with EncodingContext(cs): + self.assertEqual(ref.rstrip(sep), u"£ du blé") + + def test_split(self): + cs = self.encoding + ref = u"Des fées hébétées." + sep1 = u'é'.encode(cs) + sep2 = u'ées'.encode(cs) + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + self.assertEqual(ref.split(B(sep1), 3), [u"Des f", u"es h", u"b", u"tées."]) + self.assertEqual(ref.split(B(sep2)), [u"Des f", u" hébét", u"."]) + + def test_startsswith(self): + cs = self.encoding + # Set up the test using unicode values and indices + ref = u'café crème' + s, u, v = ref[:4], u'©af', u'caf£' + # Encode all this + enc = ref.encode(cs) + u1, v1 = u.encode(cs), v.encode(cs) + s1 = s.encode(cs) + + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + sb, ub, vb, b5 = B(s1), B(u1), B(v1), B(enc[:5]) + self.assertFalse(ref.startswith(vb)) + self.assertTrue(ref.startswith(b5)) + # Test with a mixed tuple as the argument + self.assertFalse(ref.startswith((ub, u, vb, v))) + self.assertTrue(ref.startswith((ub, b5, vb))) + self.assertTrue(ref.startswith((ub, u, b5, vb, v))) + self.assertFalse(enc.startswith((ub, vb, u, v))) + self.assertTrue(enc.startswith((u, ref[:4], v))) + self.assertTrue(enc.startswith((ub, u, ref[:4], vb, v))) + + def test_startsswith_slice(self): + cs = self.encoding + # Set up the test using unicode values and indices + ref = u'«Un café crème?»' + if len(u'«»'.encode(cs))!=2 and not test_support.is_jython: + # CPython fails on str.startswith(unicode, int, int) as it passes + # byte indices to unicode.startswith(unicode, int, int) unchanged. + # It only works if « and » encode to single bytes. Easier test: + ref = u'"Un café crème?"' + a, b = 4, -2 + s, u, v = ref[a:a+4], u'©af', u'caf£' + # Encode all this, including the indices + enc = ref.encode(cs) + u1, v1 = u.encode(cs), v.encode(cs) + a1 = len(ref[:a].encode(cs)) + b1 = - len(ref[b:].encode(cs)) + s1 = s.encode(cs) + + with EncodingContext(cs): + for B in self.BYTE_TYPES: + #print B, + sb, ub, vb = B(s1), B(u1), B(v1) + # Test the assumption on which the test is based + self.assertEqual(ref[a:b], enc[a1:b1]) + # Test slice with single argument + self.assertFalse(ref.startswith(v, a, b)) + self.assertTrue(ref.startswith(sb, a, b)) + self.assertFalse(enc.startswith(vb, a1, b1)) + self.assertTrue(enc.startswith(s, a1, b1)) + # CPython would pass: + #self.assertTrue(enc.startswith(s, a, b)) + # Test slice with a mixed tuple as the argument + self.assertFalse(ref.startswith((ub, u, vb, v), a, b)) + self.assertTrue(ref.startswith((ub, sb, vb), a, b)) + self.assertTrue(ref.startswith((ub, u, sb, vb, v), a, b)) + self.assertFalse(enc.startswith((ub, vb, u, v), a1, b1)) + self.assertTrue(enc.startswith((u, s, v), a1, b1)) + self.assertTrue(enc.startswith((ub, u, s, vb, v), a1, b1)) + # CPython would pass: + #self.assertTrue(enc.startswith((u, s, v), a, b)) + #self.assertTrue(enc.startswith((ub, u, s, vb, v), a, b)) + + def test_strip(self): + cs = self.encoding + ref = u"¤£¥¥£¤du bl饣¤¤£¥" + sep = u'¥£¤'.encode(cs) + with EncodingContext(cs): + self.assertEqual(ref.strip(sep), u"du blé") + +class DefaultDecodingLatin1(DefaultDecodingTestCase): + encoding = "latin-1" + +class DefaultDecodingUTF8(DefaultDecodingTestCase): + encoding = "utf-8" + +class DefaultDecodingCp850(DefaultDecodingTestCase): + encoding = "cp850" + + def test_main(): - test_support.run_unittest( + # We'll be enabling sys.setdefaultencoding so remember to disable + had_set = hasattr(sys, "setdefaultencoding") + try: + test_support.run_unittest( UnicodeTestCase, UnicodeIndexMixTest, UnicodeFormatTestCase, @@ -910,7 +1347,13 @@ def test_main(): UnicodeFormatStrTest, StringModuleUnicodeTest, UnicodeSpaceTest, + DefaultDecodingLatin1, + DefaultDecodingUTF8, + DefaultDecodingCp850, ) + finally: + if not had_set: + delattr(sys, "setdefaultencoding") if __name__ == "__main__": diff --git a/Lib/test/test_urllib.py b/Lib/test/test_urllib.py index a6b9b9f26..e7c66bd49 100644 --- a/Lib/test/test_urllib.py +++ b/Lib/test/test_urllib.py @@ -13,6 +13,10 @@ from test import test_support from base64 import b64encode +# Work out this is Windows, even for Jython. +WINDOWS = sys.platform == 'win32' or ( + sys.platform[:4] == 'java' and os._name == 'nt') + def hexescape(char): """Escape char as RFC 2396 specifies""" @@ -841,7 +845,7 @@ def test_quoting(self): "url2pathname() failed; %s != %s" % (expect, result)) - @unittest.skipUnless(sys.platform == 'win32', + @unittest.skipUnless(WINDOWS, 'test specific to the nturl2path library') def test_ntpath(self): given = ('/C:/', '///C:/', '/C|//') diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py index 81e71888b..ce5527714 100644 --- a/Lib/test/test_urllib2net.py +++ b/Lib/test/test_urllib2net.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - import unittest from test import test_support from test.test_urllib2 import sanepathname2url @@ -27,6 +25,13 @@ def wrapped(*args, **kwargs): return _retry_thrice(func, exc, *args, **kwargs) return wrapped +# bpo-35411: FTP tests of test_urllib2net randomly fail +# with "425 Security: Bad IP connecting" on Travis CI +skip_ftp_test_on_travis = unittest.skipIf('TRAVIS' in os.environ, + 'bpo-35411: skip FTP test ' + 'on Travis CI') + + # Connecting to remote hosts is flaky. Make it more robust by retrying # the connection several times. _urlopen_with_retry = _wrap_with_retry_thrice(urllib2.urlopen, urllib2.URLError) @@ -80,13 +85,13 @@ def test_close(self): # underlying socket # delve deep into response to fetch socket._socketobject - response = _urlopen_with_retry("http://www.python.org/") + response = _urlopen_with_retry(test_support.TEST_HTTP_URL) abused_fileobject = response.fp - self.assertTrue(abused_fileobject.__class__ is socket._fileobject) + self.assertIs(abused_fileobject.__class__, socket._fileobject) httpresponse = abused_fileobject._sock - self.assertTrue(httpresponse.__class__ is httplib.HTTPResponse) + self.assertIs(httpresponse.__class__, httplib.HTTPResponse) fileobject = httpresponse.fp - self.assertTrue(fileobject.__class__ is socket._fileobject) + self.assertIs(fileobject.__class__, socket._fileobject) self.assertTrue(not fileobject.closed) response.close() @@ -102,13 +107,12 @@ def setUp(self): # XXX The rest of these tests aren't very good -- they don't check much. # They do sometimes catch some major disasters, though. + @skip_ftp_test_on_travis def test_ftp(self): urls = [ - 'ftp://ftp.kernel.org/pub/linux/kernel/README', - 'ftp://ftp.kernel.org/pub/linux/kernel/non-existent-file', - #'ftp://ftp.kernel.org/pub/leenox/kernel/test', - 'ftp://gatekeeper.research.compaq.com/pub/DEC/SRC' - '/research-reports/00README-Legal-Rules-Regs', + 'ftp://www.pythontest.net/README', + ('ftp://www.pythontest.net/non-existent-file', + None, urllib2.URLError), ] self._test_urls(urls, self._extra_handlers()) @@ -157,15 +161,15 @@ def test_file(self): ## self._test_urls(urls, self._extra_handlers()+[bauth, dauth]) def test_urlwithfrag(self): - urlwith_frag = "https://docs.python.org/2/glossary.html#glossary" + urlwith_frag = "http://www.pythontest.net/index.html#frag" with test_support.transient_internet(urlwith_frag): req = urllib2.Request(urlwith_frag) res = urllib2.urlopen(req) self.assertEqual(res.geturl(), - "https://docs.python.org/2/glossary.html#glossary") + "http://www.pythontest.net/index.html#frag") def test_fileno(self): - req = urllib2.Request("http://www.python.org") + req = urllib2.Request(test_support.TEST_HTTP_URL) opener = urllib2.build_opener() res = opener.open(req) try: @@ -176,7 +180,7 @@ def test_fileno(self): res.close() def test_custom_headers(self): - url = "http://www.example.com" + url = test_support.TEST_HTTP_URL with test_support.transient_internet(url): opener = urllib2.build_opener() request = urllib2.Request(url) @@ -188,6 +192,8 @@ def test_custom_headers(self): opener.open(request) self.assertEqual(request.get_header('User-agent'),'Test-Agent') + # CPython 2.7 has unittest.skip('XXX: http://www.imdb.com is gone') + # ... but it isn't def test_sites_no_connection_close(self): # Some sites do not send Connection: close header. # Verify that those work properly. (#issue12576) @@ -252,15 +258,15 @@ def _extra_handlers(self): class TimeoutTest(unittest.TestCase): def test_http_basic(self): - self.assertTrue(socket.getdefaulttimeout() is None) - url = "http://www.python.org" + self.assertIsNone(socket.getdefaulttimeout()) + url = test_support.TEST_HTTP_URL with test_support.transient_internet(url, timeout=None): u = _urlopen_with_retry(url) - self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) + self.assertIsNone(u.fp._sock.fp._sock.gettimeout()) def test_http_default_timeout(self): - self.assertTrue(socket.getdefaulttimeout() is None) - url = "http://www.python.org" + self.assertIsNone(socket.getdefaulttimeout()) + url = test_support.TEST_HTTP_URL with test_support.transient_internet(url): socket.setdefaulttimeout(60) try: @@ -270,32 +276,34 @@ def test_http_default_timeout(self): self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 60) def test_http_no_timeout(self): - self.assertTrue(socket.getdefaulttimeout() is None) - url = "http://www.python.org" + self.assertIsNone(socket.getdefaulttimeout()) + url = test_support.TEST_HTTP_URL with test_support.transient_internet(url): socket.setdefaulttimeout(60) try: u = _urlopen_with_retry(url, timeout=None) finally: socket.setdefaulttimeout(None) - self.assertTrue(u.fp._sock.fp._sock.gettimeout() is None) + self.assertIsNone(u.fp._sock.fp._sock.gettimeout()) def test_http_timeout(self): - url = "http://www.python.org" + url = test_support.TEST_HTTP_URL with test_support.transient_internet(url): u = _urlopen_with_retry(url, timeout=120) self.assertEqual(u.fp._sock.fp._sock.gettimeout(), 120) - FTP_HOST = "ftp://ftp.mirror.nl/pub/gnu/" + FTP_HOST = 'ftp://www.pythontest.net/' + @skip_ftp_test_on_travis def test_ftp_basic(self): - self.assertTrue(socket.getdefaulttimeout() is None) + self.assertIsNone(socket.getdefaulttimeout()) with test_support.transient_internet(self.FTP_HOST, timeout=None): u = _urlopen_with_retry(self.FTP_HOST) - self.assertTrue(u.fp.fp._sock.gettimeout() is None) + self.assertIsNone(u.fp.fp._sock.gettimeout()) + @skip_ftp_test_on_travis def test_ftp_default_timeout(self): - self.assertTrue(socket.getdefaulttimeout() is None) + self.assertIsNone(socket.getdefaulttimeout()) with test_support.transient_internet(self.FTP_HOST): socket.setdefaulttimeout(60) try: @@ -304,16 +312,18 @@ def test_ftp_default_timeout(self): socket.setdefaulttimeout(None) self.assertEqual(u.fp.fp._sock.gettimeout(), 60) + @skip_ftp_test_on_travis def test_ftp_no_timeout(self): - self.assertTrue(socket.getdefaulttimeout() is None) + self.assertIsNone(socket.getdefaulttimeout(),) with test_support.transient_internet(self.FTP_HOST): socket.setdefaulttimeout(60) try: u = _urlopen_with_retry(self.FTP_HOST, timeout=None) finally: socket.setdefaulttimeout(None) - self.assertTrue(u.fp.fp._sock.gettimeout() is None) + self.assertIsNone(u.fp.fp._sock.gettimeout()) + @skip_ftp_test_on_travis def test_ftp_timeout(self): with test_support.transient_internet(self.FTP_HOST): u = _urlopen_with_retry(self.FTP_HOST, timeout=60) diff --git a/Lib/test/test_zipimport_jy.py b/Lib/test/test_zipimport_jy.py index 2e8b0fed6..fe36511bf 100644 --- a/Lib/test/test_zipimport_jy.py +++ b/Lib/test/test_zipimport_jy.py @@ -47,12 +47,14 @@ def __init__(self): class ZipImporterDictTest(unittest.TestCase): def test_subclass_assign_attribute(self): class A(zipimporter): pass - path = os.path.abspath('tests/modjy/lib_python_folder/test_modules.zip') + path = test_support.findfile("zipdir.zip") A(path).somevar = 1 def test_main(): - test_support.run_unittest(SyspathZipimportTest) - test_support.run_unittest(ZipImporterDictTest) + test_support.run_unittest( + SyspathZipimportTest, + ZipImporterDictTest + ) if __name__ == "__main__": test_main() diff --git a/Lib/test/test_zipimport_support.py b/Lib/test/test_zipimport_support.py index 3bd342252..f510c38dc 100644 --- a/Lib/test/test_zipimport_support.py +++ b/Lib/test/test_zipimport_support.py @@ -240,6 +240,14 @@ class Test: print data self.assertIn(expected, data) + def assertNormalisedIn(self, target, data): + # bdb/pdb applies normcase to its filename before displaying. + # Also, it emerges as FS-encoded bytes, so do the same to the target. + target = os.path.normcase(target) + if not isinstance(target, bytes): + target = target.encode(sys.getfilesystemencoding()) + self.assertIn(target, data) + def test_pdb_issue4201(self): test_src = textwrap.dedent("""\ def f(): @@ -248,22 +256,22 @@ def f(): import pdb pdb.runcall(f) """) + with temp_dir() as d: script_name = make_script(d, 'script', test_src) p = spawn_python(script_name) p.stdin.write('l\n') data = kill_python(p) - # bdb/pdb applies normcase to its filename before displaying - # See CPython Issue 14255 (back-ported for Jython) - self.assertIn(os.path.normcase(script_name.encode('utf-8')), data) + # Back-port from CPython 3 (see CPython Issue 14255). + self.assertNormalisedIn(script_name, data) + zip_name, run_name = make_zip_script(d, "test_zip", script_name, '__main__.py') p = spawn_python(zip_name) p.stdin.write('l\n') data = kill_python(p) - # bdb/pdb applies normcase to its filename before displaying - # See CPython Issue 14255 (back-ported for Jython) - self.assertIn(os.path.normcase(run_name.encode('utf-8')), data) + # Back-port from CPython 3 (see CPython Issue 14255). + self.assertNormalisedIn(run_name, data) def test_main(): diff --git a/Lib/test/test_zlib_jy.py b/Lib/test/test_zlib_jy.py index 334b29178..5e5c1bceb 100644 --- a/Lib/test/test_zlib_jy.py +++ b/Lib/test/test_zlib_jy.py @@ -28,6 +28,44 @@ def _test_array(self, compress, decompress): compressed = array('c', compress('jython')) self.assertEqual('jython', decompress(compressed)) + def test_decompress_gzip(self): + co = zlib.compressobj(wbits=31) # window 15 with gzip wrapper. + c = co.compress("Jenny: 867-5309") + c += co.flush() + dco = zlib.decompressobj(wbits=31) + d = dco.decompress(c) + self.assertEqual(b'', dco.unused_data, msg="dco.unused_data not empty after decompress.") + self.assertEqual(b'', dco.unconsumed_tail, msg="dco.unconsumed_tail not empty after decompress.") + self.assertEqual("Jenny: 867-5309", d) + + def test_decompress_badlen(self): + # Manipulating last two bytes to create invalid initial size check. + # RFC-1952: + # 0 1 2 3 4 5 6 7 + # +---+---+---+---+---+---+---+---+ + # | CRC32 | ISIZE | + # +---+---+---+---+---+---+---+---+turn: + # + c=b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x0bJ\xacT(O,V\xc8H-J\x05\x00\xc2\xb0\x1e\xe5\x0d\x00\x00\x00' + dco = zlib.decompressobj(wbits=31) + self.assertRaisesRegexp(zlib.error, 'Error -3 while decompressing data: incorrect length check', + dco.decompress, c) + + def test_decompress_badcrc(self): + # Manipulating last crc bytes to create a crc check exception. + # RFC-1952: + # 0 1 2 3 4 5 6 7 + # +---+---+---+---+---+---+---+---+ + # | CRC32 | ISIZE | + # +---+---+---+---+---+---+---+---+turn: + # + c=b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x0bJ\xacT(O,V\xc8H-J\x05\x00\xc2\xb0\x1f\xe5\x0c\x00\x00\x00' + dco = zlib.decompressobj(wbits=31) + self.assertRaisesRegexp(zlib.error, 'Error -3 while decompressing data: incorrect data check', + dco.decompress, c) + + + def test_main(): test_support.run_unittest(ArrayTestCase) diff --git a/Lib/threading.py b/Lib/threading.py index 54e6dc793..5396f2363 100644 --- a/Lib/threading.py +++ b/Lib/threading.py @@ -222,11 +222,6 @@ def __bootstrap(self): self.run() except SystemExit: pass - except InterruptedException: - # Quiet InterruptedExceptions if they're caused by - # _systemrestart - if not jython.shouldRestart: - raise except: # If sys.stderr is no more (most likely from interpreter # shutdown) use self.__stderr. Otherwise still use sys (as in diff --git a/Lib/urllib.py b/Lib/urllib.py new file mode 100644 index 000000000..a66589e63 --- /dev/null +++ b/Lib/urllib.py @@ -0,0 +1,1673 @@ +"""Open an arbitrary URL. + +See the following document for more info on URLs: +"Names and Addresses, URIs, URLs, URNs, URCs", at +http://www.w3.org/pub/WWW/Addressing/Overview.html + +See also the HTTP spec (from which the error codes are derived): +"HTTP - Hypertext Transfer Protocol", at +http://www.w3.org/pub/WWW/Protocols/ + +Related standards and specs: +- RFC1808: the "relative URL" spec. (authoritative status) +- RFC1738 - the "URL standard". (authoritative status) +- RFC1630 - the "URI spec". (informational status) + +The object returned by URLopener().open(file) will differ per +protocol. All you know is that is has methods read(), readline(), +readlines(), fileno(), close() and info(). The read*(), fileno() +and close() methods work like those of open files. +The info() method returns a mimetools.Message object which can be +used to query various info about the object, if available. +(mimetools.Message objects are queried with the getheader() method.) +""" + +import string +import socket +import os +import time +import sys +import base64 +import re + +from urlparse import urljoin as basejoin + +__all__ = ["urlopen", "URLopener", "FancyURLopener", "urlretrieve", + "urlcleanup", "quote", "quote_plus", "unquote", "unquote_plus", + "urlencode", "url2pathname", "pathname2url", "splittag", + "localhost", "thishost", "ftperrors", "basejoin", "unwrap", + "splittype", "splithost", "splituser", "splitpasswd", "splitport", + "splitnport", "splitquery", "splitattr", "splitvalue", + "getproxies"] + +__version__ = '1.17' # XXX This version is not always updated :-( + +MAXFTPCACHE = 10 # Trim the ftp cache beyond this size + +# Work out this is Windows, even for Jython. +WINDOWS = sys.platform == 'win32' or ( + sys.platform[:4] == 'java' and os._name == 'nt') + +# Helper for non-unix systems +if WINDOWS: + from nturl2path import url2pathname, pathname2url +elif os.name == 'riscos': + from rourl2path import url2pathname, pathname2url +else: + def url2pathname(pathname): + """OS-specific conversion from a relative URL of the 'file' scheme + to a file system path; not recommended for general use.""" + return unquote(pathname) + + def pathname2url(pathname): + """OS-specific conversion from a file system path to a relative URL + of the 'file' scheme; not recommended for general use.""" + return quote(pathname) + +# This really consists of two pieces: +# (1) a class which handles opening of all sorts of URLs +# (plus assorted utilities etc.) +# (2) a set of functions for parsing URLs +# XXX Should these be separated out into different modules? + + +# Shortcut for basic usage +_urlopener = None +def urlopen(url, data=None, proxies=None, context=None): + """Create a file-like object for the specified URL to read from.""" + from warnings import warnpy3k + warnpy3k("urllib.urlopen() has been removed in Python 3.0 in " + "favor of urllib2.urlopen()", stacklevel=2) + + global _urlopener + if proxies is not None or context is not None: + opener = FancyURLopener(proxies=proxies, context=context) + elif not _urlopener: + opener = FancyURLopener() + _urlopener = opener + else: + opener = _urlopener + if data is None: + return opener.open(url) + else: + return opener.open(url, data) +def urlretrieve(url, filename=None, reporthook=None, data=None, context=None): + global _urlopener + if context is not None: + opener = FancyURLopener(context=context) + elif not _urlopener: + _urlopener = opener = FancyURLopener() + else: + opener = _urlopener + return opener.retrieve(url, filename, reporthook, data) +def urlcleanup(): + if _urlopener: + _urlopener.cleanup() + _safe_quoters.clear() + ftpcache.clear() + +# check for SSL +try: + import ssl +except: + _have_ssl = False +else: + _have_ssl = True + +# exception raised when downloaded size does not match content-length +class ContentTooShortError(IOError): + def __init__(self, message, content): + IOError.__init__(self, message) + self.content = content + +ftpcache = {} +class URLopener: + """Class to open URLs. + This is a class rather than just a subroutine because we may need + more than one set of global protocol-specific options. + Note -- this is a base class for those who don't want the + automatic handling of errors type 302 (relocated) and 401 + (authorization needed).""" + + __tempfiles = None + + version = "Python-urllib/%s" % __version__ + + # Constructor + def __init__(self, proxies=None, context=None, **x509): + if proxies is None: + proxies = getproxies() + assert hasattr(proxies, 'has_key'), "proxies must be a mapping" + self.proxies = proxies + self.key_file = x509.get('key_file') + self.cert_file = x509.get('cert_file') + self.context = context + self.addheaders = [('User-Agent', self.version), ('Accept', '*/*')] + self.__tempfiles = [] + self.__unlink = os.unlink # See cleanup() + self.tempcache = None + # Undocumented feature: if you assign {} to tempcache, + # it is used to cache files retrieved with + # self.retrieve(). This is not enabled by default + # since it does not work for changing documents (and I + # haven't got the logic to check expiration headers + # yet). + self.ftpcache = ftpcache + # Undocumented feature: you can use a different + # ftp cache by assigning to the .ftpcache member; + # in case you want logically independent URL openers + # XXX This is not threadsafe. Bah. + + def __del__(self): + self.close() + + def close(self): + self.cleanup() + + def cleanup(self): + # This code sometimes runs when the rest of this module + # has already been deleted, so it can't use any globals + # or import anything. + if self.__tempfiles: + for file in self.__tempfiles: + try: + self.__unlink(file) + except OSError: + pass + del self.__tempfiles[:] + if self.tempcache: + self.tempcache.clear() + + def addheader(self, *args): + """Add a header to be used by the HTTP interface only + e.g. u.addheader('Accept', 'sound/basic')""" + self.addheaders.append(args) + + # External interface + def open(self, fullurl, data=None): + """Use URLopener().open(file) instead of open(file, 'r').""" + fullurl = unwrap(toBytes(fullurl)) + # percent encode url, fixing lame server errors for e.g, like space + # within url paths. + fullurl = quote(fullurl, safe="%/:=&?~#+!$,;'@()*[]|") + if self.tempcache and fullurl in self.tempcache: + filename, headers = self.tempcache[fullurl] + fp = open(filename, 'rb') + return addinfourl(fp, headers, fullurl) + urltype, url = splittype(fullurl) + if not urltype: + urltype = 'file' + if urltype in self.proxies: + proxy = self.proxies[urltype] + urltype, proxyhost = splittype(proxy) + host, selector = splithost(proxyhost) + url = (host, fullurl) # Signal special case to open_*() + else: + proxy = None + name = 'open_' + urltype + self.type = urltype + name = name.replace('-', '_') + if not hasattr(self, name): + if proxy: + return self.open_unknown_proxy(proxy, fullurl, data) + else: + return self.open_unknown(fullurl, data) + try: + if data is None: + return getattr(self, name)(url) + else: + return getattr(self, name)(url, data) + except socket.error, msg: + raise IOError, ('socket error', msg), sys.exc_info()[2] + + def open_unknown(self, fullurl, data=None): + """Overridable interface to open unknown URL type.""" + type, url = splittype(fullurl) + raise IOError, ('url error', 'unknown url type', type) + + def open_unknown_proxy(self, proxy, fullurl, data=None): + """Overridable interface to open unknown URL type.""" + type, url = splittype(fullurl) + raise IOError, ('url error', 'invalid proxy for %s' % type, proxy) + + # External interface + def retrieve(self, url, filename=None, reporthook=None, data=None): + """retrieve(url) returns (filename, headers) for a local object + or (tempfilename, headers) for a remote object.""" + url = unwrap(toBytes(url)) + if self.tempcache and url in self.tempcache: + return self.tempcache[url] + type, url1 = splittype(url) + if filename is None and (not type or type == 'file'): + try: + fp = self.open_local_file(url1) + hdrs = fp.info() + fp.close() + return url2pathname(splithost(url1)[1]), hdrs + except IOError: + pass + fp = self.open(url, data) + try: + headers = fp.info() + if filename: + tfp = open(filename, 'wb') + else: + import tempfile + garbage, path = splittype(url) + garbage, path = splithost(path or "") + path, garbage = splitquery(path or "") + path, garbage = splitattr(path or "") + suffix = os.path.splitext(path)[1] + (fd, filename) = tempfile.mkstemp(suffix) + self.__tempfiles.append(filename) + tfp = os.fdopen(fd, 'wb') + try: + result = filename, headers + if self.tempcache is not None: + self.tempcache[url] = result + bs = 1024*8 + size = -1 + read = 0 + blocknum = 0 + if "content-length" in headers: + size = int(headers["Content-Length"]) + if reporthook: + reporthook(blocknum, bs, size) + while 1: + block = fp.read(bs) + if block == "": + break + read += len(block) + tfp.write(block) + blocknum += 1 + if reporthook: + reporthook(blocknum, bs, size) + finally: + tfp.close() + finally: + fp.close() + + # raise exception if actual size does not match content-length header + if size >= 0 and read < size: + raise ContentTooShortError("retrieval incomplete: got only %i out " + "of %i bytes" % (read, size), result) + + return result + + # Each method named open_ knows how to open that type of URL + + def open_http(self, url, data=None): + """Use HTTP protocol.""" + import httplib + user_passwd = None + proxy_passwd= None + if isinstance(url, str): + host, selector = splithost(url) + if host: + user_passwd, host = splituser(host) + host = unquote(host) + realhost = host + else: + host, selector = url + # check whether the proxy contains authorization information + proxy_passwd, host = splituser(host) + # now we proceed with the url we want to obtain + urltype, rest = splittype(selector) + url = rest + user_passwd = None + if urltype.lower() != 'http': + realhost = None + else: + realhost, rest = splithost(rest) + if realhost: + user_passwd, realhost = splituser(realhost) + if user_passwd: + selector = "%s://%s%s" % (urltype, realhost, rest) + if proxy_bypass(realhost): + host = realhost + + #print "proxy via http:", host, selector + if not host: raise IOError, ('http error', 'no host given') + + if proxy_passwd: + proxy_passwd = unquote(proxy_passwd) + proxy_auth = base64.b64encode(proxy_passwd).strip() + else: + proxy_auth = None + + if user_passwd: + user_passwd = unquote(user_passwd) + auth = base64.b64encode(user_passwd).strip() + else: + auth = None + h = httplib.HTTP(host) + if data is not None: + h.putrequest('POST', selector) + h.putheader('Content-Type', 'application/x-www-form-urlencoded') + h.putheader('Content-Length', '%d' % len(data)) + else: + h.putrequest('GET', selector) + if proxy_auth: h.putheader('Proxy-Authorization', 'Basic %s' % proxy_auth) + if auth: h.putheader('Authorization', 'Basic %s' % auth) + if realhost: h.putheader('Host', realhost) + for args in self.addheaders: h.putheader(*args) + h.endheaders(data) + errcode, errmsg, headers = h.getreply() + fp = h.getfile() + if errcode == -1: + if fp: fp.close() + # something went wrong with the HTTP status line + raise IOError, ('http protocol error', 0, + 'got a bad status line', None) + # According to RFC 2616, "2xx" code indicates that the client's + # request was successfully received, understood, and accepted. + if (200 <= errcode < 300): + return addinfourl(fp, headers, "http:" + url, errcode) + else: + if data is None: + return self.http_error(url, fp, errcode, errmsg, headers) + else: + return self.http_error(url, fp, errcode, errmsg, headers, data) + + def http_error(self, url, fp, errcode, errmsg, headers, data=None): + """Handle http errors. + Derived class can override this, or provide specific handlers + named http_error_DDD where DDD is the 3-digit error code.""" + # First check if there's a specific handler for this error + name = 'http_error_%d' % errcode + if hasattr(self, name): + method = getattr(self, name) + if data is None: + result = method(url, fp, errcode, errmsg, headers) + else: + result = method(url, fp, errcode, errmsg, headers, data) + if result: return result + return self.http_error_default(url, fp, errcode, errmsg, headers) + + def http_error_default(self, url, fp, errcode, errmsg, headers): + """Default error handler: close the connection and raise IOError.""" + fp.close() + raise IOError, ('http error', errcode, errmsg, headers) + + if _have_ssl: + def open_https(self, url, data=None): + """Use HTTPS protocol.""" + + import httplib + user_passwd = None + proxy_passwd = None + if isinstance(url, str): + host, selector = splithost(url) + if host: + user_passwd, host = splituser(host) + host = unquote(host) + realhost = host + else: + host, selector = url + # here, we determine, whether the proxy contains authorization information + proxy_passwd, host = splituser(host) + urltype, rest = splittype(selector) + url = rest + user_passwd = None + if urltype.lower() != 'https': + realhost = None + else: + realhost, rest = splithost(rest) + if realhost: + user_passwd, realhost = splituser(realhost) + if user_passwd: + selector = "%s://%s%s" % (urltype, realhost, rest) + #print "proxy via https:", host, selector + if not host: raise IOError, ('https error', 'no host given') + if proxy_passwd: + proxy_passwd = unquote(proxy_passwd) + proxy_auth = base64.b64encode(proxy_passwd).strip() + else: + proxy_auth = None + if user_passwd: + user_passwd = unquote(user_passwd) + auth = base64.b64encode(user_passwd).strip() + else: + auth = None + h = httplib.HTTPS(host, 0, + key_file=self.key_file, + cert_file=self.cert_file, + context=self.context) + if data is not None: + h.putrequest('POST', selector) + h.putheader('Content-Type', + 'application/x-www-form-urlencoded') + h.putheader('Content-Length', '%d' % len(data)) + else: + h.putrequest('GET', selector) + if proxy_auth: h.putheader('Proxy-Authorization', 'Basic %s' % proxy_auth) + if auth: h.putheader('Authorization', 'Basic %s' % auth) + if realhost: h.putheader('Host', realhost) + for args in self.addheaders: h.putheader(*args) + h.endheaders(data) + errcode, errmsg, headers = h.getreply() + fp = h.getfile() + if errcode == -1: + if fp: fp.close() + # something went wrong with the HTTP status line + raise IOError, ('http protocol error', 0, + 'got a bad status line', None) + # According to RFC 2616, "2xx" code indicates that the client's + # request was successfully received, understood, and accepted. + if (200 <= errcode < 300): + return addinfourl(fp, headers, "https:" + url, errcode) + else: + if data is None: + return self.http_error(url, fp, errcode, errmsg, headers) + else: + return self.http_error(url, fp, errcode, errmsg, headers, + data) + + def open_file(self, url): + """Use local file or FTP depending on form of URL.""" + if not isinstance(url, str): + raise IOError, ('file error', 'proxy support for file protocol currently not implemented') + if url[:2] == '//' and url[2:3] != '/' and url[2:12].lower() != 'localhost/': + return self.open_ftp(url) + else: + return self.open_local_file(url) + + def open_local_file(self, url): + """Use local file.""" + import mimetypes, mimetools, email.utils + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + host, file = splithost(url) + localname = url2pathname(file) + try: + stats = os.stat(localname) + except OSError, e: + raise IOError(e.errno, e.strerror, e.filename) + size = stats.st_size + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + mtype = mimetypes.guess_type(url)[0] + headers = mimetools.Message(StringIO( + 'Content-Type: %s\nContent-Length: %d\nLast-modified: %s\n' % + (mtype or 'text/plain', size, modified))) + if not host: + urlfile = file + if file[:1] == '/': + urlfile = 'file://' + file + elif file[:2] == './': + raise ValueError("local file url may start with / or file:. Unknown url of type: %s" % url) + return addinfourl(open(localname, 'rb'), + headers, urlfile) + host, port = splitport(host) + if not port \ + and socket.gethostbyname(host) in (localhost(), thishost()): + urlfile = file + if file[:1] == '/': + urlfile = 'file://' + file + return addinfourl(open(localname, 'rb'), + headers, urlfile) + raise IOError, ('local file error', 'not on local host') + + def open_ftp(self, url): + """Use FTP protocol.""" + if not isinstance(url, str): + raise IOError, ('ftp error', 'proxy support for ftp protocol currently not implemented') + import mimetypes, mimetools + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + host, path = splithost(url) + if not host: raise IOError, ('ftp error', 'no host given') + host, port = splitport(host) + user, host = splituser(host) + if user: user, passwd = splitpasswd(user) + else: passwd = None + host = unquote(host) + user = user or '' + passwd = passwd or '' + host = socket.gethostbyname(host) + if not port: + import ftplib + port = ftplib.FTP_PORT + else: + port = int(port) + path, attrs = splitattr(path) + path = unquote(path) + dirs = path.split('/') + dirs, file = dirs[:-1], dirs[-1] + if dirs and not dirs[0]: dirs = dirs[1:] + if dirs and not dirs[0]: dirs[0] = '/' + key = user, host, port, '/'.join(dirs) + # XXX thread unsafe! + if len(self.ftpcache) > MAXFTPCACHE: + # Prune the cache, rather arbitrarily + for k in self.ftpcache.keys(): + if k != key: + v = self.ftpcache[k] + del self.ftpcache[k] + v.close() + try: + if not key in self.ftpcache: + self.ftpcache[key] = \ + ftpwrapper(user, passwd, host, port, dirs) + if not file: type = 'D' + else: type = 'I' + for attr in attrs: + attr, value = splitvalue(attr) + if attr.lower() == 'type' and \ + value in ('a', 'A', 'i', 'I', 'd', 'D'): + type = value.upper() + (fp, retrlen) = self.ftpcache[key].retrfile(file, type) + mtype = mimetypes.guess_type("ftp:" + url)[0] + headers = "" + if mtype: + headers += "Content-Type: %s\n" % mtype + if retrlen is not None and retrlen >= 0: + headers += "Content-Length: %d\n" % retrlen + headers = mimetools.Message(StringIO(headers)) + return addinfourl(fp, headers, "ftp:" + url) + except ftperrors(), msg: + raise IOError, ('ftp error', msg), sys.exc_info()[2] + + def open_data(self, url, data=None): + """Use "data" URL.""" + if not isinstance(url, str): + raise IOError, ('data error', 'proxy support for data protocol currently not implemented') + # ignore POSTed data + # + # syntax of data URLs: + # dataurl := "data:" [ mediatype ] [ ";base64" ] "," data + # mediatype := [ type "/" subtype ] *( ";" parameter ) + # data := *urlchar + # parameter := attribute "=" value + import mimetools + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + try: + [type, data] = url.split(',', 1) + except ValueError: + raise IOError, ('data error', 'bad data URL') + if not type: + type = 'text/plain;charset=US-ASCII' + semi = type.rfind(';') + if semi >= 0 and '=' not in type[semi:]: + encoding = type[semi+1:] + type = type[:semi] + else: + encoding = '' + msg = [] + msg.append('Date: %s'%time.strftime('%a, %d %b %Y %H:%M:%S GMT', + time.gmtime(time.time()))) + msg.append('Content-type: %s' % type) + if encoding == 'base64': + data = base64.decodestring(data) + else: + data = unquote(data) + msg.append('Content-Length: %d' % len(data)) + msg.append('') + msg.append(data) + msg = '\n'.join(msg) + f = StringIO(msg) + headers = mimetools.Message(f, 0) + #f.fileno = None # needed for addinfourl + return addinfourl(f, headers, url) + + +class FancyURLopener(URLopener): + """Derived class with handlers for errors we can handle (perhaps).""" + + def __init__(self, *args, **kwargs): + URLopener.__init__(self, *args, **kwargs) + self.auth_cache = {} + self.tries = 0 + self.maxtries = 10 + + def http_error_default(self, url, fp, errcode, errmsg, headers): + """Default error handling -- don't raise an exception.""" + return addinfourl(fp, headers, "http:" + url, errcode) + + def http_error_302(self, url, fp, errcode, errmsg, headers, data=None): + """Error 302 -- relocated (temporarily).""" + self.tries += 1 + try: + if self.maxtries and self.tries >= self.maxtries: + if hasattr(self, "http_error_500"): + meth = self.http_error_500 + else: + meth = self.http_error_default + return meth(url, fp, 500, + "Internal Server Error: Redirect Recursion", + headers) + result = self.redirect_internal(url, fp, errcode, errmsg, + headers, data) + return result + finally: + self.tries = 0 + + def redirect_internal(self, url, fp, errcode, errmsg, headers, data): + if 'location' in headers: + newurl = headers['location'] + elif 'uri' in headers: + newurl = headers['uri'] + else: + return + fp.close() + # In case the server sent a relative URL, join with original: + newurl = basejoin(self.type + ":" + url, newurl) + + # For security reasons we do not allow redirects to protocols + # other than HTTP, HTTPS or FTP. + newurl_lower = newurl.lower() + if not (newurl_lower.startswith('http://') or + newurl_lower.startswith('https://') or + newurl_lower.startswith('ftp://')): + raise IOError('redirect error', errcode, + errmsg + " - Redirection to url '%s' is not allowed" % + newurl, + headers) + + return self.open(newurl) + + def http_error_301(self, url, fp, errcode, errmsg, headers, data=None): + """Error 301 -- also relocated (permanently).""" + return self.http_error_302(url, fp, errcode, errmsg, headers, data) + + def http_error_303(self, url, fp, errcode, errmsg, headers, data=None): + """Error 303 -- also relocated (essentially identical to 302).""" + return self.http_error_302(url, fp, errcode, errmsg, headers, data) + + def http_error_307(self, url, fp, errcode, errmsg, headers, data=None): + """Error 307 -- relocated, but turn POST into error.""" + if data is None: + return self.http_error_302(url, fp, errcode, errmsg, headers, data) + else: + return self.http_error_default(url, fp, errcode, errmsg, headers) + + def http_error_401(self, url, fp, errcode, errmsg, headers, data=None): + """Error 401 -- authentication required. + This function supports Basic authentication only.""" + if not 'www-authenticate' in headers: + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + stuff = headers['www-authenticate'] + import re + match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff) + if not match: + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + scheme, realm = match.groups() + if scheme.lower() != 'basic': + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + name = 'retry_' + self.type + '_basic_auth' + if data is None: + return getattr(self,name)(url, realm) + else: + return getattr(self,name)(url, realm, data) + + def http_error_407(self, url, fp, errcode, errmsg, headers, data=None): + """Error 407 -- proxy authentication required. + This function supports Basic authentication only.""" + if not 'proxy-authenticate' in headers: + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + stuff = headers['proxy-authenticate'] + import re + match = re.match('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', stuff) + if not match: + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + scheme, realm = match.groups() + if scheme.lower() != 'basic': + URLopener.http_error_default(self, url, fp, + errcode, errmsg, headers) + name = 'retry_proxy_' + self.type + '_basic_auth' + if data is None: + return getattr(self,name)(url, realm) + else: + return getattr(self,name)(url, realm, data) + + def retry_proxy_http_basic_auth(self, url, realm, data=None): + host, selector = splithost(url) + newurl = 'http://' + host + selector + proxy = self.proxies['http'] + urltype, proxyhost = splittype(proxy) + proxyhost, proxyselector = splithost(proxyhost) + i = proxyhost.find('@') + 1 + proxyhost = proxyhost[i:] + user, passwd = self.get_user_passwd(proxyhost, realm, i) + if not (user or passwd): return None + proxyhost = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + proxyhost + self.proxies['http'] = 'http://' + proxyhost + proxyselector + if data is None: + return self.open(newurl) + else: + return self.open(newurl, data) + + def retry_proxy_https_basic_auth(self, url, realm, data=None): + host, selector = splithost(url) + newurl = 'https://' + host + selector + proxy = self.proxies['https'] + urltype, proxyhost = splittype(proxy) + proxyhost, proxyselector = splithost(proxyhost) + i = proxyhost.find('@') + 1 + proxyhost = proxyhost[i:] + user, passwd = self.get_user_passwd(proxyhost, realm, i) + if not (user or passwd): return None + proxyhost = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + proxyhost + self.proxies['https'] = 'https://' + proxyhost + proxyselector + if data is None: + return self.open(newurl) + else: + return self.open(newurl, data) + + def retry_http_basic_auth(self, url, realm, data=None): + host, selector = splithost(url) + i = host.find('@') + 1 + host = host[i:] + user, passwd = self.get_user_passwd(host, realm, i) + if not (user or passwd): return None + host = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + host + newurl = 'http://' + host + selector + if data is None: + return self.open(newurl) + else: + return self.open(newurl, data) + + def retry_https_basic_auth(self, url, realm, data=None): + host, selector = splithost(url) + i = host.find('@') + 1 + host = host[i:] + user, passwd = self.get_user_passwd(host, realm, i) + if not (user or passwd): return None + host = quote(user, safe='') + ':' + quote(passwd, safe='') + '@' + host + newurl = 'https://' + host + selector + if data is None: + return self.open(newurl) + else: + return self.open(newurl, data) + + def get_user_passwd(self, host, realm, clear_cache=0): + key = realm + '@' + host.lower() + if key in self.auth_cache: + if clear_cache: + del self.auth_cache[key] + else: + return self.auth_cache[key] + user, passwd = self.prompt_user_passwd(host, realm) + if user or passwd: self.auth_cache[key] = (user, passwd) + return user, passwd + + def prompt_user_passwd(self, host, realm): + """Override this in a GUI environment!""" + import getpass + try: + user = raw_input("Enter username for %s at %s: " % (realm, + host)) + passwd = getpass.getpass("Enter password for %s in %s at %s: " % + (user, realm, host)) + return user, passwd + except KeyboardInterrupt: + print + return None, None + + +# Utility functions + +_localhost = None +def localhost(): + """Return the IP address of the magic hostname 'localhost'.""" + global _localhost + if _localhost is None: + _localhost = socket.gethostbyname('localhost') + return _localhost + +_thishost = None +def thishost(): + """Return the IP address of the current host.""" + global _thishost + if _thishost is None: + try: + _thishost = socket.gethostbyname(socket.gethostname()) + except socket.gaierror: + _thishost = socket.gethostbyname('localhost') + return _thishost + +_ftperrors = None +def ftperrors(): + """Return the set of errors raised by the FTP class.""" + global _ftperrors + if _ftperrors is None: + import ftplib + _ftperrors = ftplib.all_errors + return _ftperrors + +_noheaders = None +def noheaders(): + """Return an empty mimetools.Message object.""" + global _noheaders + if _noheaders is None: + import mimetools + try: + from cStringIO import StringIO + except ImportError: + from StringIO import StringIO + _noheaders = mimetools.Message(StringIO(), 0) + _noheaders.fp.close() # Recycle file descriptor + return _noheaders + + +# Utility classes + +class ftpwrapper: + """Class used by open_ftp() for cache of open FTP connections.""" + + def __init__(self, user, passwd, host, port, dirs, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + persistent=True): + self.user = user + self.passwd = passwd + self.host = host + self.port = port + self.dirs = dirs + self.timeout = timeout + self.refcount = 0 + self.keepalive = persistent + try: + self.init() + except: + self.close() + raise + + def init(self): + import ftplib + self.busy = 0 + self.ftp = ftplib.FTP() + self.ftp.connect(self.host, self.port, self.timeout) + self.ftp.login(self.user, self.passwd) + _target = '/'.join(self.dirs) + self.ftp.cwd(_target) + + def retrfile(self, file, type): + import ftplib + self.endtransfer() + if type in ('d', 'D'): cmd = 'TYPE A'; isdir = 1 + else: cmd = 'TYPE ' + type; isdir = 0 + try: + self.ftp.voidcmd(cmd) + except ftplib.all_errors: + self.init() + self.ftp.voidcmd(cmd) + conn = None + if file and not isdir: + # Try to retrieve as a file + try: + cmd = 'RETR ' + file + conn, retrlen = self.ftp.ntransfercmd(cmd) + except ftplib.error_perm, reason: + if str(reason)[:3] != '550': + raise IOError, ('ftp error', reason), sys.exc_info()[2] + if not conn: + # Set transfer mode to ASCII! + self.ftp.voidcmd('TYPE A') + # Try a directory listing. Verify that directory exists. + if file: + pwd = self.ftp.pwd() + try: + try: + self.ftp.cwd(file) + except ftplib.error_perm, reason: + raise IOError, ('ftp error', reason), sys.exc_info()[2] + finally: + self.ftp.cwd(pwd) + cmd = 'LIST ' + file + else: + cmd = 'LIST' + conn, retrlen = self.ftp.ntransfercmd(cmd) + self.busy = 1 + ftpobj = addclosehook(conn.makefile('rb'), self.file_close) + self.refcount += 1 + conn.close() + # Pass back both a suitably decorated object and a retrieval length + return (ftpobj, retrlen) + + def endtransfer(self): + self.busy = 0 + + def close(self): + self.keepalive = False + if self.refcount <= 0: + self.real_close() + + def file_close(self): + self.endtransfer() + self.refcount -= 1 + if self.refcount <= 0 and not self.keepalive: + self.real_close() + + def real_close(self): + self.endtransfer() + try: + self.ftp.close() + except ftperrors(): + pass + +class addbase: + """Base class for addinfo and addclosehook.""" + + def __init__(self, fp): + self.fp = fp + self.read = self.fp.read + self.readline = self.fp.readline + if hasattr(self.fp, "readlines"): self.readlines = self.fp.readlines + if hasattr(self.fp, "fileno"): + self.fileno = self.fp.fileno + else: + self.fileno = lambda: None + if hasattr(self.fp, "__iter__"): + self.__iter__ = self.fp.__iter__ + if hasattr(self.fp, "next"): + self.next = self.fp.next + + def __repr__(self): + return '<%s at %r whose fp = %r>' % (self.__class__.__name__, + id(self), self.fp) + + def close(self): + self.read = None + self.readline = None + self.readlines = None + self.fileno = None + if self.fp: self.fp.close() + self.fp = None + +class addclosehook(addbase): + """Class to add a close hook to an open file.""" + + def __init__(self, fp, closehook, *hookargs): + addbase.__init__(self, fp) + self.closehook = closehook + self.hookargs = hookargs + + def close(self): + try: + closehook = self.closehook + hookargs = self.hookargs + if closehook: + self.closehook = None + self.hookargs = None + closehook(*hookargs) + finally: + addbase.close(self) + + +class addinfo(addbase): + """class to add an info() method to an open file.""" + + def __init__(self, fp, headers): + addbase.__init__(self, fp) + self.headers = headers + + def info(self): + return self.headers + +class addinfourl(addbase): + """class to add info() and geturl() methods to an open file.""" + + def __init__(self, fp, headers, url, code=None): + addbase.__init__(self, fp) + self.headers = headers + self.url = url + self.code = code + + def info(self): + return self.headers + + def getcode(self): + return self.code + + def geturl(self): + return self.url + + +# Utilities to parse URLs (most of these return None for missing parts): +# unwrap('') --> 'type://host/path' +# splittype('type:opaquestring') --> 'type', 'opaquestring' +# splithost('//host[:port]/path') --> 'host[:port]', '/path' +# splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]' +# splitpasswd('user:passwd') -> 'user', 'passwd' +# splitport('host:port') --> 'host', 'port' +# splitquery('/path?query') --> '/path', 'query' +# splittag('/path#tag') --> '/path', 'tag' +# splitattr('/path;attr1=value1;attr2=value2;...') -> +# '/path', ['attr1=value1', 'attr2=value2', ...] +# splitvalue('attr=value') --> 'attr', 'value' +# unquote('abc%20def') -> 'abc def' +# quote('abc def') -> 'abc%20def') + +try: + unicode +except NameError: + def _is_unicode(x): + return 0 +else: + def _is_unicode(x): + return isinstance(x, unicode) + +def toBytes(url): + """toBytes(u"URL") --> 'URL'.""" + # Most URL schemes require ASCII. If that changes, the conversion + # can be relaxed + if _is_unicode(url): + try: + url = url.encode("ASCII") + except UnicodeError: + raise UnicodeError("URL " + repr(url) + + " contains non-ASCII characters") + return url + +def unwrap(url): + """unwrap('') --> 'type://host/path'.""" + url = url.strip() + if url[:1] == '<' and url[-1:] == '>': + url = url[1:-1].strip() + if url[:4] == 'URL:': url = url[4:].strip() + return url + +_typeprog = None +def splittype(url): + """splittype('type:opaquestring') --> 'type', 'opaquestring'.""" + global _typeprog + if _typeprog is None: + import re + _typeprog = re.compile('^([^/:]+):') + + match = _typeprog.match(url) + if match: + scheme = match.group(1) + return scheme.lower(), url[len(scheme) + 1:] + return None, url + +_hostprog = None +def splithost(url): + """splithost('//host[:port]/path') --> 'host[:port]', '/path'.""" + global _hostprog + if _hostprog is None: + import re + _hostprog = re.compile('^//([^/?]*)(.*)$') + + match = _hostprog.match(url) + if match: + host_port = match.group(1) + path = match.group(2) + if path and not path.startswith('/'): + path = '/' + path + return host_port, path + return None, url + +_userprog = None +def splituser(host): + """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" + global _userprog + if _userprog is None: + import re + _userprog = re.compile('^(.*)@(.*)$') + + match = _userprog.match(host) + if match: return match.group(1, 2) + return None, host + +_passwdprog = None +def splitpasswd(user): + """splitpasswd('user:passwd') -> 'user', 'passwd'.""" + global _passwdprog + if _passwdprog is None: + import re + _passwdprog = re.compile('^([^:]*):(.*)$',re.S) + + match = _passwdprog.match(user) + if match: return match.group(1, 2) + return user, None + +# splittag('/path#tag') --> '/path', 'tag' +_portprog = None +def splitport(host): + """splitport('host:port') --> 'host', 'port'.""" + global _portprog + if _portprog is None: + import re + _portprog = re.compile('^(.*):([0-9]*)$') + + match = _portprog.match(host) + if match: + host, port = match.groups() + if port: + return host, port + return host, None + +_nportprog = None +def splitnport(host, defport=-1): + """Split host and port, returning numeric port. + Return given default port if no ':' found; defaults to -1. + Return numerical port if a valid number are found after ':'. + Return None if ':' but not a valid number.""" + global _nportprog + if _nportprog is None: + import re + _nportprog = re.compile('^(.*):(.*)$') + + match = _nportprog.match(host) + if match: + host, port = match.group(1, 2) + if port: + try: + nport = int(port) + except ValueError: + nport = None + return host, nport + return host, defport + +_queryprog = None +def splitquery(url): + """splitquery('/path?query') --> '/path', 'query'.""" + global _queryprog + if _queryprog is None: + import re + _queryprog = re.compile('^(.*)\?([^?]*)$') + + match = _queryprog.match(url) + if match: return match.group(1, 2) + return url, None + +_tagprog = None +def splittag(url): + """splittag('/path#tag') --> '/path', 'tag'.""" + global _tagprog + if _tagprog is None: + import re + _tagprog = re.compile('^(.*)#([^#]*)$') + + match = _tagprog.match(url) + if match: return match.group(1, 2) + return url, None + +def splitattr(url): + """splitattr('/path;attr1=value1;attr2=value2;...') -> + '/path', ['attr1=value1', 'attr2=value2', ...].""" + words = url.split(';') + return words[0], words[1:] + +_valueprog = None +def splitvalue(attr): + """splitvalue('attr=value') --> 'attr', 'value'.""" + global _valueprog + if _valueprog is None: + import re + _valueprog = re.compile('^([^=]*)=(.*)$') + + match = _valueprog.match(attr) + if match: return match.group(1, 2) + return attr, None + +# urlparse contains a duplicate of this method to avoid a circular import. If +# you update this method, also update the copy in urlparse. This code +# duplication does not exist in Python3. + +_hexdig = '0123456789ABCDEFabcdef' +_hextochr = dict((a + b, chr(int(a + b, 16))) + for a in _hexdig for b in _hexdig) +_asciire = re.compile('([\x00-\x7f]+)') + +def unquote(s): + """unquote('abc%20def') -> 'abc def'.""" + if _is_unicode(s): + if '%' not in s: + return s + bits = _asciire.split(s) + res = [bits[0]] + append = res.append + for i in range(1, len(bits), 2): + append(unquote(str(bits[i])).decode('latin1')) + append(bits[i + 1]) + return ''.join(res) + + bits = s.split('%') + # fastpath + if len(bits) == 1: + return s + res = [bits[0]] + append = res.append + for item in bits[1:]: + try: + append(_hextochr[item[:2]]) + append(item[2:]) + except KeyError: + append('%') + append(item) + return ''.join(res) + +def unquote_plus(s): + """unquote('%7e/abc+def') -> '~/abc def'""" + s = s.replace('+', ' ') + return unquote(s) + +always_safe = ('ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789' '_.-') +_safe_map = {} +for i, c in zip(xrange(256), str(bytearray(xrange(256)))): + _safe_map[c] = c if (i < 128 and c in always_safe) else '%{:02X}'.format(i) +_safe_quoters = {} + +def quote(s, safe='/'): + """quote('abc def') -> 'abc%20def' + + Each part of a URL, e.g. the path info, the query, etc., has a + different set of reserved characters that must be quoted. + + RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists + the following reserved characters. + + reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | + "$" | "," + + Each of these characters is reserved in some component of a URL, + but not necessarily in all of them. + + By default, the quote function is intended for quoting the path + section of a URL. Thus, it will not encode '/'. This character + is reserved, but in typical usage the quote function is being + called on a path where the existing slash characters are used as + reserved characters. + """ + # fastpath + if not s: + if s is None: + raise TypeError('None object cannot be quoted') + return s + cachekey = (safe, always_safe) + try: + (quoter, safe) = _safe_quoters[cachekey] + except KeyError: + safe_map = _safe_map.copy() + safe_map.update([(c, c) for c in safe]) + quoter = safe_map.__getitem__ + safe = always_safe + safe + _safe_quoters[cachekey] = (quoter, safe) + if not s.rstrip(safe): + return s + return ''.join(map(quoter, s)) + +def quote_plus(s, safe=''): + """Quote the query fragment of a URL; replacing ' ' with '+'""" + if ' ' in s: + s = quote(s, safe + ' ') + return s.replace(' ', '+') + return quote(s, safe) + +def urlencode(query, doseq=0): + """Encode a sequence of two-element tuples or dictionary into a URL query string. + + If any values in the query arg are sequences and doseq is true, each + sequence element is converted to a separate parameter. + + If the query arg is a sequence of two-element tuples, the order of the + parameters in the output will match the order of parameters in the + input. + """ + + if hasattr(query,"items"): + # mapping objects + query = query.items() + else: + # it's a bother at times that strings and string-like objects are + # sequences... + try: + # non-sequence items should not work with len() + # non-empty strings will fail this + if len(query) and not isinstance(query[0], tuple): + raise TypeError + # zero-length sequences of all types will get here and succeed, + # but that's a minor nit - since the original implementation + # allowed empty dicts that type of behavior probably should be + # preserved for consistency + except TypeError: + ty,va,tb = sys.exc_info() + raise TypeError, "not a valid non-string sequence or mapping object", tb + + l = [] + if not doseq: + # preserve old behavior + for k, v in query: + k = quote_plus(str(k)) + v = quote_plus(str(v)) + l.append(k + '=' + v) + else: + for k, v in query: + k = quote_plus(str(k)) + if isinstance(v, str): + v = quote_plus(v) + l.append(k + '=' + v) + elif _is_unicode(v): + # is there a reasonable way to convert to ASCII? + # encode generates a string, but "replace" or "ignore" + # lose information and "strict" can raise UnicodeError + v = quote_plus(v.encode("ASCII","replace")) + l.append(k + '=' + v) + else: + try: + # is this a sufficient test for sequence-ness? + len(v) + except TypeError: + # not a sequence + v = quote_plus(str(v)) + l.append(k + '=' + v) + else: + # loop over the sequence + for elt in v: + l.append(k + '=' + quote_plus(str(elt))) + return '&'.join(l) + +# Proxy handling +def getproxies_environment(): + """Return a dictionary of scheme -> proxy server URL mappings. + + Scan the environment for variables named _proxy; + this seems to be the standard convention. In order to prefer lowercase + variables, we process the environment in two passes, first matches any + and second matches only lower case proxies. + + If you need a different way, you can pass a proxies dictionary to the + [Fancy]URLopener constructor. + """ + # Get all variables + proxies = {} + for name, value in os.environ.items(): + name = name.lower() + if value and name[-6:] == '_proxy': + proxies[name[:-6]] = value + + # CVE-2016-1000110 - If we are running as CGI script, forget HTTP_PROXY + # (non-all-lowercase) as it may be set from the web server by a "Proxy:" + # header from the client + # If "proxy" is lowercase, it will still be used thanks to the next block + if 'REQUEST_METHOD' in os.environ: + proxies.pop('http', None) + + # Get lowercase variables + for name, value in os.environ.items(): + if name[-6:] == '_proxy': + name = name.lower() + if value: + proxies[name[:-6]] = value + else: + proxies.pop(name[:-6], None) + + return proxies + +def proxy_bypass_environment(host, proxies=None): + """Test if proxies should not be used for a particular host. + + Checks the proxies dict for the value of no_proxy, which should be a + list of comma separated DNS suffixes, or '*' for all hosts. + """ + if proxies is None: + proxies = getproxies_environment() + # don't bypass, if no_proxy isn't specified + try: + no_proxy = proxies['no'] + except KeyError: + return 0 + # '*' is special case for always bypass + if no_proxy == '*': + return 1 + # strip port off host + hostonly, port = splitport(host) + # check if the host ends with any of the DNS suffixes + no_proxy_list = [proxy.strip() for proxy in no_proxy.split(',')] + for name in no_proxy_list: + if name: + name = re.escape(name) + pattern = r'(.+\.)?%s$' % name + if (re.match(pattern, hostonly, re.I) + or re.match(pattern, host, re.I)): + return 1 + # otherwise, don't bypass + return 0 + + +if sys.platform == 'darwin': + from _scproxy import _get_proxy_settings, _get_proxies + + def proxy_bypass_macosx_sysconf(host): + """ + Return True iff this host shouldn't be accessed using a proxy + + This function uses the MacOSX framework SystemConfiguration + to fetch the proxy information. + """ + import re + import socket + from fnmatch import fnmatch + + hostonly, port = splitport(host) + + def ip2num(ipAddr): + parts = ipAddr.split('.') + parts = map(int, parts) + if len(parts) != 4: + parts = (parts + [0, 0, 0, 0])[:4] + return (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3] + + proxy_settings = _get_proxy_settings() + + # Check for simple host names: + if '.' not in host: + if proxy_settings['exclude_simple']: + return True + + hostIP = None + + for value in proxy_settings.get('exceptions', ()): + # Items in the list are strings like these: *.local, 169.254/16 + if not value: continue + + m = re.match(r"(\d+(?:\.\d+)*)(/\d+)?", value) + if m is not None: + if hostIP is None: + try: + hostIP = socket.gethostbyname(hostonly) + hostIP = ip2num(hostIP) + except socket.error: + continue + + base = ip2num(m.group(1)) + mask = m.group(2) + if mask is None: + mask = 8 * (m.group(1).count('.') + 1) + + else: + mask = int(mask[1:]) + mask = 32 - mask + + if (hostIP >> mask) == (base >> mask): + return True + + elif fnmatch(host, value): + return True + + return False + + def getproxies_macosx_sysconf(): + """Return a dictionary of scheme -> proxy server URL mappings. + + This function uses the MacOSX framework SystemConfiguration + to fetch the proxy information. + """ + return _get_proxies() + + def proxy_bypass(host): + """Return True, if a host should be bypassed. + + Checks proxy settings gathered from the environment, if specified, or + from the MacOSX framework SystemConfiguration. + """ + proxies = getproxies_environment() + if proxies: + return proxy_bypass_environment(host, proxies) + else: + return proxy_bypass_macosx_sysconf(host) + + def getproxies(): + return getproxies_environment() or getproxies_macosx_sysconf() + +elif os.name == 'nt': + def getproxies_registry(): + """Return a dictionary of scheme -> proxy server URL mappings. + + Win32 uses the registry to store proxies. + + """ + proxies = {} + try: + import _winreg + except ImportError: + # Std module, so should be around - but you never know! + return proxies + try: + internetSettings = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + proxyEnable = _winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0] + if proxyEnable: + # Returned as Unicode but problems if not converted to ASCII + proxyServer = str(_winreg.QueryValueEx(internetSettings, + 'ProxyServer')[0]) + if '=' in proxyServer: + # Per-protocol settings + for p in proxyServer.split(';'): + protocol, address = p.split('=', 1) + # See if address has a type:// prefix + import re + if not re.match('^([^/:]+)://', address): + address = '%s://%s' % (protocol, address) + proxies[protocol] = address + else: + # Use one setting for all protocols + if proxyServer[:5] == 'http:': + proxies['http'] = proxyServer + else: + proxies['http'] = 'http://%s' % proxyServer + proxies['https'] = 'https://%s' % proxyServer + proxies['ftp'] = 'ftp://%s' % proxyServer + internetSettings.Close() + except (WindowsError, ValueError, TypeError): + # Either registry key not found etc, or the value in an + # unexpected format. + # proxies already set up to be empty so nothing to do + pass + return proxies + + def getproxies(): + """Return a dictionary of scheme -> proxy server URL mappings. + + Returns settings gathered from the environment, if specified, + or the registry. + + """ + return getproxies_environment() or getproxies_registry() + + def proxy_bypass_registry(host): + try: + import _winreg + import re + except ImportError: + # Std modules, so should be around - but you never know! + return 0 + try: + internetSettings = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + proxyEnable = _winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0] + proxyOverride = str(_winreg.QueryValueEx(internetSettings, + 'ProxyOverride')[0]) + # ^^^^ Returned as Unicode but problems if not converted to ASCII + except WindowsError: + return 0 + if not proxyEnable or not proxyOverride: + return 0 + # try to make a host list from name and IP address. + rawHost, port = splitport(host) + host = [rawHost] + try: + addr = socket.gethostbyname(rawHost) + if addr != rawHost: + host.append(addr) + except socket.error: + pass + try: + fqdn = socket.getfqdn(rawHost) + if fqdn != rawHost: + host.append(fqdn) + except socket.error: + pass + # make a check value list from the registry entry: replace the + # '' string by the localhost entry and the corresponding + # canonical entry. + proxyOverride = proxyOverride.split(';') + # now check if we match one of the registry values. + for test in proxyOverride: + if test == '': + if '.' not in rawHost: + return 1 + test = test.replace(".", r"\.") # mask dots + test = test.replace("*", r".*") # change glob sequence + test = test.replace("?", r".") # change glob char + for val in host: + # print "%s <--> %s" %( test, val ) + if re.match(test, val, re.I): + return 1 + return 0 + + def proxy_bypass(host): + """Return True, if the host should be bypassed. + + Checks proxy settings gathered from the environment, if specified, + or the registry. + """ + proxies = getproxies_environment() + if proxies: + return proxy_bypass_environment(host, proxies) + else: + return proxy_bypass_registry(host) + +else: + # By default use environment variables + getproxies = getproxies_environment + proxy_bypass = proxy_bypass_environment + +# Test and time quote() and unquote() +def test1(): + s = '' + for i in range(256): s = s + chr(i) + s = s*4 + t0 = time.time() + qs = quote(s) + uqs = unquote(qs) + t1 = time.time() + if uqs != s: + print 'Wrong!' + print repr(s) + print repr(qs) + print repr(uqs) + print round(t1 - t0, 3), 'sec' + + +def reporthook(blocknum, blocksize, totalsize): + # Report during remote transfers + print "Block number: %d, Block size: %d, Total size: %d" % ( + blocknum, blocksize, totalsize) diff --git a/Lib/zipfile.py b/Lib/zipfile.py index c0828a723..5f9b68ebf 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -1425,7 +1425,11 @@ def _get_codename(self, pathname, basename): /python/lib/string, return (/python/lib/string.pyc, string). """ file_py = pathname + ".py" - file_pyc = pathname + (".pyc" if not _is_jython else "$py.class") + if _is_jython: + import imp + file_pyc = imp._makeCompiledFilename(file_py) + else: + file_pyc = pathname + ".pyc" file_pyo = pathname + ".pyo" if os.path.isfile(file_pyo) and \ os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime: diff --git a/Lib/zlib.py b/Lib/zlib.py index 44c8e9978..2a495854f 100644 --- a/Lib/zlib.py +++ b/Lib/zlib.py @@ -24,9 +24,6 @@ from java.util.zip import Adler32, CRC32, Deflater, Inflater, DataFormatException -class error(Exception): - pass - DEFLATED = 8 MAX_WBITS = 15 @@ -54,7 +51,8 @@ class error(Exception): } -_ADLER_BASE = 65521 # largest prime smaller than 65536 +_ADLER_BASE = 65521 # largest prime smaller than 65536 +_MASK32 = 0xffffffffL # 2**32 - 1 used for unsigned mod 2**32 def adler32(s, value=1): # Although Java has an implmentation in java.util.zip.Adler32, @@ -110,6 +108,7 @@ def decompress(string, wbits=0, bufsize=16384): # > system will be set to 255 (unknown). If a gzip stream is being # > written, strm->adler is a crc32 instead of an adler32. + class compressobj(object): # All jython uses wbits for is in deciding whether to skip the # header if it's negative or to set gzip. But we still raise @@ -118,10 +117,11 @@ class compressobj(object): GZIP_HEADER = "\x1f\x8b\x08\x00\x00\x00\x00\x00\x04\x03" # NB: this format is little-endian, not big-endian as we might - # expect for network oriented protocols, as specified by RFCs; - # CRC32.getValue() returns an unsigned int as a long, so cope - # accordingly - GZIP_TRAILER_FORMAT = struct.Struct(">debugFile, str @@ -32,18 +34,14 @@ def splitIntoWords(name): elif i == l-1: n = name[wordstart:i+1] if n: - #print " ", i, c, n wordstart = i if c == '-' and n != '': n += '-' if c == ' ' or c == '-': wordstart = i+1 - #print " ", n wordlist.append(n) - return wordlist - def readUnicodeDict(file): d = {} for l in fileinput.input(file): @@ -62,22 +60,17 @@ def readUnicodeDict(file): continue wordlist = splitIntoWords(name) - #print name, wordlist d[name] = (int(v, 16), wordlist, []) return d -#readUnicodeDict("nametest.txt") -#sys.exit() - def count(dict, index): c = dict.get(index) if c is None: c = 0 c += 1 dict[index] = c - def dumpUnicodeDict(title, dict): lst = [] i = 0 @@ -92,8 +85,6 @@ def dumpUnicodeDict(title, dict): print "%.4X %s %s" % (v, k, p) - - class MphEmitter: def readint(self): @@ -155,17 +146,20 @@ def writeFile(self, inf, outf): self.inf = inf self.readconst(); - outf.write(struct.pack("!hhhhhh", self.n, - self.m, - self.minchar, - self.maxchar, - self.alphasz, - self.maxlen)) - self.readg().writeto(outf) + outf.write(struct.pack("!hhhhh", self.n, + self.m, + self.minchar, + self.alphasz, + self.maxlen)) + G = self.readg() + debug("G len: %d" % (G.size()/2)) + G.writeto(outf) outf.write(struct.pack("!h", self.d)) for t in range(self.d): - self.readT(t).writeto(outf) + T = self.readT(t) + debug("T%d len: %d" % (t, T.size()/2)) + T.writeto(outf) class Table: @@ -181,9 +175,15 @@ def write_Short(self, v): def write_UShort(self, v): self.buf.write(struct.pack("!H", v)) + def write_Int32(self, v): + self.buf.write(struct.pack("!i", v)) + + def write_UInt32(self, v): + self.buf.write(struct.pack("!I", v)) + def writeto(self, file): file.write('t') - file.write(struct.pack("!H", self.size())) + file.write(struct.pack("!I", self.size())) file.write(self.buf.getvalue()) def size(self): @@ -196,21 +196,16 @@ def calculateSize(dict): cnt += len(name) return cnt - - def calculateWords(unicodeDict): words = {} for key, (value, wordlist, rawlist) in unicodeDict.items(): for name in wordlist: wordlist = words.setdefault(name, []) wordlist.append(key) - return words - def replaceWord(word, index, charlist): replaced = 0 - for char in charlist: (v, wordlist, rawlist) = unicodeDict[char] try: @@ -224,11 +219,9 @@ def replaceWord(word, index, charlist): def compress(): #dumpUnicodeDict("UnicodeDict before", unicodeDict) words = calculateWords(unicodeDict) - lenp = [(len(v), k, v) for k, v in words.items()] lenp.sort() lenp.reverse() - wordidx = len(chars) for (length, word, value) in lenp: # Do not lookup single char words or words only used once @@ -238,19 +231,12 @@ def compress(): # be just as big. if len(word) == 2 and wordidx >= 238: continue - - #print length, word, len(value) - replaceWord(word, wordidx, value) wordmap[wordidx] = word - wordidx += 1 - #dumpUnicodeDict("UnicodeDict after", unicodeDict) - def writeUcnhashDat(): - cutoff = 255 - ((len(chars) + len(wordmap)) >> 8) debug("wordmap entries: %d" % len(wordmap)) @@ -259,20 +245,17 @@ def writeUcnhashDat(): worddata = Table() wordoffs = Table() wordfile = open("words.in", "wt"); - size = 0 l = [(k,v) for k,v in wordmap.items()] l.sort() for k,v in l: print >>wordfile, v wordoffs.write_UShort(worddata.size()) - mapv = ''.join(map(lambda x: chr(chardict.get(x)), v)) worddata.write_Str(mapv) - wordfile.close() - os.system("mph.exe -d3 -S1 -m4 -a < words.in > words.hash") + os.system(mph_exec+" -d3 -S1 -m4 -a < words.in > words.hash") outf = open("ucnhash.dat", "wb+") @@ -280,8 +263,8 @@ def writeUcnhashDat(): m.writeFile(open("words.hash"), outf) debug("wordhash size %d" % outf.tell()) - debug("wordoffs size %d" % wordoffs.size()) - debug("worddata size %d" % worddata.size()) + debug("wordoffs size %d" % (wordoffs.size()/2)) + debug("worddata size %d" % (worddata.size())) wordoffs.writeto(outf) worddata.writeto(outf) @@ -292,7 +275,7 @@ def writeUcnhashDat(): savewordlist = wordlist[:] # Map remaining strings to a list of bytes in chardict - # range: range(0,37) + # range: range(0, 40) l = len(wordlist) for i in range(l-1, -1, -1): part = wordlist[i] @@ -301,7 +284,6 @@ def writeUcnhashDat(): if i > 0 and type(wordlist[i-1]) == type(""): ipart[0:0] = [0] # index of space wordlist[i:i+1] = ipart - # Encode high values as two bytes for v in wordlist: if v <= cutoff: @@ -316,7 +298,6 @@ def writeUcnhashDat(): lst.append((rawlist, wordlist, key, value)) maxklen = max(maxklen, len(key)) lst.sort() - outf.write(struct.pack("!hhh", len(chars), cutoff, maxklen)); raw = Table() @@ -326,7 +307,7 @@ def writeUcnhashDat(): for r in rawlist: raw.write_Str(chr(r)) datasize.append((len(rawlist), value)) - debug("%d %s %r" % (i, key, rawlist)) + #debug("%d %s %r" % (i, key, rawlist)) i += 1 debug("Raw size = %d" % raw.size()) raw.writeto(outf) @@ -336,25 +317,45 @@ def writeUcnhashDat(): offset = 0 maxlen = 0 + maxvl = 0 # for debugging + # Formerly it was sufficient for rawindex and codepoint + # to be 16 bit. + # We leave the old 16 bit write instructions here as + # comments in case future debugging is necessary. + # Note that rawindex blocksize therefore shrunk from + # 5 to 3, which was adjusted in ucnhash.java accordingly. + # In line 'v = v | (long(size) << (j*5))' the '5' seemingly + # refers to blocksize, but for some reason it must not be + # adjusted to 3. + # (3 would break things, while it works well with 5) for i in range(0, len(datasize), 12): saveoffset = offset - rawindex.write_UShort(offset) + #rawindex.write_UShort(offset) + rawindex.write_UInt32(offset) v = 0L j = 0 for (size, value) in datasize[i:i+12]: + # we keep track of max value to confirm + # that 32 bit codepoint table is needed + if value > maxvl: + maxvl = value offset += size v = v | (long(size) << (j*5)) maxlen = max(maxlen, size) - codepoint.write_UShort(value) + #codepoint.write_UShort(value) + codepoint.write_UInt32(value) j += 1 - debug("%d %d %x" % (i/ 12, saveoffset, v)) - rawindex.write_UShort((v >> 48) & 0xFFFF) - rawindex.write_UShort((v >> 32) & 0xFFFF) - rawindex.write_UShort((v >> 16) & 0xFFFF) - rawindex.write_UShort(v & 0xFFFF) - - debug("rawindex size % d" % rawindex.size()) + #debug("%d %d %x" % (i/ 12, saveoffset, v)) + #rawindex.write_UShort((v >> 48) & 0xFFFF) + #rawindex.write_UShort((v >> 32) & 0xFFFF) + #rawindex.write_UShort((v >> 16) & 0xFFFF) + #rawindex.write_UShort(v & 0xFFFF) + rawindex.write_UInt32((v >> 32) & 0xFFFFFFFF) + rawindex.write_UInt32(v & 0xFFFFFFFF) + debug("maxval % d" % maxvl) + debug("rawindex size % d" % (rawindex.size()/4)) + debug("codepoint size % d" % (codepoint.size()/4)) rawindex.writeto(outf) codepoint.writeto(outf) @@ -362,9 +363,8 @@ def writeUcnhashDat(): outf.close(); - if __name__ == "__main__": - chars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-" + chars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()" chardict = {} for c in chars: chardict[c] = chars.index(c) @@ -372,12 +372,16 @@ def writeUcnhashDat(): debugChars = [] # [0x41, 0x20AC] debugFile = open("ucnhash.lst", "wt") + #debugFile = sys.stdout wordmap = {} - unicodeDataFile = "UnicodeData-3.0.0.txt" + # Called 2017 with UnicodeData.txt for Unicode 9.0 + unicodeDataFile = "UnicodeData.txt" if len(sys.argv) > 1: unicodeDataFile = sys.argv[1] + if len(sys.argv) > 2: + mph_exec = sys.argv[2] unicodeDict = readUnicodeDict(unicodeDataFile) print "Size:", calculateSize(unicodeDict) @@ -389,7 +393,63 @@ def writeUcnhashDat(): sys.exit(0) - - - - +# Debugging-hints: +#----------------- +# (with debugFile = sys.stdout, omitting mph-output) + +# Output for "UnicodeData-3.0.0.txt": +# Size: 259126 +# compressed +# wordmap entries: 1384 +# wordmap cutoffs: 250 +# * d=3 +# * n=1703 +# * m=1384 +# * c=1.23 +# * maxlen=4 +# * minklen=2 +# * maxklen=18 +# * minchar=45 +# * maxchar=90 +# G len: 1703 +# T0 len: 184 +# T1 len: 184 +# T2 len: 184 +# wordhash size 4542 +# wordoffs size 1384 +# worddata size 7375 +# Raw size = 58531 +# maxval 65533 +# rawindex size 2577 +# codepoint size 10298 +# raw entries 10298 +# done + + +# Output for "UnicodeData.txt", Unicode 9.0: +# Size: 755323 +# compressed +# wordmap entries: 3708 +# wordmap cutoffs: 241 +# * d=3 +# * n=4561 +# * m=3708 +# * c=1.23 +# * maxlen=4 +# * minklen=2 +# * maxklen=18 +# * minchar=32 +# * maxchar=90 +# G len: 4561 +# T0 len: 236 +# T1 len: 236 +# T2 len: 236 +# wordhash size 10570 +# wordoffs size 3708 +# worddata size 19399 +# Raw size = 184818 +# maxval 917999 +# rawindex size 7389 +# codepoint size 29545 +# raw entries 29545 +# done diff --git a/NEWS b/NEWS index 62b96e5b0..88baaffb0 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,252 @@ Jython NEWS -For more details, please see https://hg.python.org/jython +The features new in a given release are generally listed under the section for the "b1" release +of that version. + +For more details of issue [ n ], please see https://hg.python.org/jython, or for tags [ GH-n ] see +https://github.com/jythontools/jython + +Jython 2.7.3a1 + Bugs fixed + - [ ] + + New Features + - + +Jython 2.7.2 + same as 2.7.2rc1 + +Jython 2.7.2rc1 + Bugs fixed + - [ 2858 ] test_ssl failure due to embedding Bouncy Castle (doc change only) + - [ GH-156 ] Race condition in PyStringMap keys method + - [ 2862 ] Jython fails on Linux for normal user when installed by root + +Jython 2.7.2b3 + Bugs fixed + - [ 2810 ] NoSuchMethodError in test_jython_initializer (Java 10+) + - [ 2808 ] lib2to3 test failures on Windows JDK 11 + - [ 2846 ] Main module __name __ is not "__main__" under Java Scripting API + - [ 2828 ] Update netty JARs to 4.1.45 + - [ 2044 ] CVE-2013-2027 Current umask sets privileges of class files and cache + - [ 2834 ] Import of Java classes is not thread safe + - [ 2820 ] Import fails with UnicodeDecodeError if sys.path contains invalid UTF-8 bytes + - [ 2826 ] Unicode hex string decode failure + - [ 2836 ] Java Swing library works only in interactive jython session + +Jython 2.7.2b2 + Bugs fixed + - [ 2814 ] maven/build.xml does not PGP-sign the publication + +Jython 2.7.2b1 + Bugs fixed + - [ 2806 ] Installer contains dependencies unshaded (Java 8) + - [ 2666 ] Oracle JDK 7 out of support so no longer available on Travis + - [ 2294 ] Importation of modules from directories with non-ASCII characters fails + - [ 2055 ] isinstance() and issubclass() fail with abc.ABCMeta + - [ 2569 ] jython launcher fails on Windows if JAVA_HOME is set + - [ 2505 ] PySystemState is lost + - [ 2796 ] Request for oversize arrays not handled in BaseBytes and PyByteArray + - [ 2730 ] datetime.strptime('%b') behaviour inconsistent with CPython on Windows JDK 9+ + - [ 2613 ] MANIFEST.MF contains unfilled placeholders + - [ 2330 ] full-build fails to copy CPython License + - [ 2651 ] Travis builds failing with *** buffer overflow detected *** + - [ 2703 ] JycompileAntTask cannot find ...ant.taskdefs.MatchingTask + - [ 2708 ] test_urllib2net fails (on Travis CI) + - [ 2764 ] Readme is not displayed when using the GUI installer + - [ 2345 ] Installing pip fails if JYTHON_HOME points to old installation + - [ 2774 ] test_ssl failures from weak certificate + - [ 2768 ] Allow bytearray + and += to accept buffer protocol objects + - [ 2742 ] JARs for bouncycastle out of date (upgrade to 1.16) + - [ 2762 ] Upgrade Apache commons-compress to 1.18 + - [ GH-108 ] Updates to JNR/JFFI to improve ARM HF support + - [ 2445 ] Eclipse's DelegatingFeatureMap has MRO conflict (and IBM's MQQueue) + - [ GH-121 ] Allow struct unpack and unpack_from bytearray and buffer + - [ 2635 ] AST.lineno ignored by compile + - [ 2744 ] Support buffer type in marshal.dump(s) + - [ 2077 ] marshal doesn't raise error when fed unmarshalable object + - [ 2732 ] Regression in large module support for pip + - [ GH-131 ] Support Unicode in zxJDBC exceptions. + - [ 2654 ] Imported modules allow access to submodules + - [ 2362 ] Import * doesn't work on JDK9 for java.*, jdk.* namespaces + - [ 2630 ] Cannot import java.awt.* on Java 9 + - [ 2663 ] Remove dependency on javax.xml.bind.DatatypeConverter + - [ 2726 ] os.uname() throws IllegalArgumentException on Windows (Chinese localisation) + - [ 2719 ] Divergence of __str__ and __repr__ from CPython + - [ 2714 ] Locale and java version failures in test_os_jy + - [ GH-111 ] Proper processing of gzip trailer without resubmission + - [ 2231 ] __doc__ of PyString objects is always "The most base type" + - [ 2230 ] Jython evaluation blocks under heavy load with high multi-core systems + - [ 2506 ] ensurepip is reporting an error + - [ 1609 ] Partial parsing does not work with function decorators + - [ 2494 ] Support for pydoc_data + - [ 2492 ] NPE for PythonInterpreter after new PyInteger + - [ 2707 ] jython.py shebang line invalid on Linux + - [ 1748 ] subprocess and os.system don't show output + - [ 2343 ] PYTHONPATH is overwritten on Windows + - [ 2346 ] Launcher not resilient to bad environment variable settings + - [ 2709 ] test_chdir tolerates absent DOS 8.3 filename + - [ 2706 ] Use python.path instead of JYTHONPATH + - [ 2410 ] Regression in PySystemStateTest (leading slash) + - [ 2639 ] Incorrect result when using != comparison against Java {List, Set, Map} + - [ 2672 ] Integer formatting emits two minus signs with -2^31 + - [ 2688 ] ClassCastException when adding list of non-PyObjects + - [ 2659 ] Determine console encoding without access violation (Java 9) + - [ 2662 ] IllegalAccessException accessing public abstract method via PyReflectedFunction + - [ 2501 ] JAVA_STACK doesn't work (fixed for Windows launcher only) + - [ 1866 ] Parser does not have mismatch token error messages caught by BaseRecognizer + - [ 1930 ] traceback raises exception in os.py + - [ 2419 ] List expected failures by OS platform in regrtest.py + - [ 2611 ] mkdir() operation in /Lib/os.py has different behavior when running in Docker container + - [ 2655 ] __findattr__ is final (update documentation) + - [ 2646 ] Test failure in test_os_jy after utf-8 decode + - [ 2469 ] jython launcher fails on Windows if JAVA_HOME is set + - [ 2650 ] Detail message is not set on PyException from PythonInterpreter + - [ 2403 ] VerifyError when implementing interfaces containing default methods (Java 8) + - [ 2715 ] Restrict array.array support for buffer protocol + + New Features + - The main program behaves more like CPython in many small ways, including a more correct + treatment of the -i option. This simplifies support, and may also make it unnecessary for + users to work around differences from CPython. + - python.startup registry property (and JYTHONSTARTUP environment variable) added. + - Only the Jython command (class org.python.util.jython) now reads the environment variable + JYTHONPATH, not the core runtime, and it respects the -E option (ignore environment). This + change is for consistency with CPython and with our handling of other environment variables. + A pure Java application that creates its own interpreter may use the system or registry + key "python.path" to add to sys.path, as documented. + - We no longer recommend overriding toString in PyObject sub-classes as a way of defining + string forms. Override __repr__, and if necessary __str__, as is usual in Python. We + recommend toString should return the same as __str__ (or __unicode__). + - Experimentally, we use Gradle to build a JAR and POM that may be cited as a dependency by + other projects. The Jython project would like to know if this is being done suitably + for downstream use. + - The registry setting (or Java property) "python.verbose", and direct use of the global + org.python.core.Options.verbose are DEPRECATED: use a Java logging properties file instead. + Console messages are now produced via java.util.logging (JUL), and the logger "org.python" + or its descendants. The jython command configures a ConsoleLogger for "org.python" and by + default a format for messages generally similar to that in v2.7.1, preceded by the logger + name and JUL severity. The volume of messages is controlled by your logging preferences, but + by default is unchanged from v2.7.1. Each -v option on the command line makes the logging + one step finer on the JUL scale. Error messages from Python and stack traces are unaffected. + When embedded in your application, Jython makes no logging configuration changes: messages + from the "org.python" name space merge with those of your application. + - There is much improved support for locale, but as a backward-incompatible change, it is + provided as an opt-in. Define property python.locale.control=settable on the command line + or via the Jython registry, to enable. This may become the default in a later version. + - The default location of the Jython package cache has moved from the installation directory + to the current working directory and is called ".jython_cache". Previously, Jython installed + system-wide either exposed the cache as world read-write (a security risk) or disabled it. + - BouncyCastle SSL support is incomplete as bundled. The Jython JAR is not signed, and may not + be trusted by your JVM as a security provider. This manifests as a PEMException: "Unable to + create OpenSSL PBDKF: PBKDF-OpenSSL SecretKeyFactory not available" during certain + operations. If this is a problem, place genuine BouncyCastle JARs on the class path, and + Jython will use those in preference to the classes we include. The slim JAR is not affected. + +Jython 2.7.2a1 + Bugs fixed + - [ 2632 ] Handle unicode data appropriately in csv module + - [ 2638 ] str not default-decoded in str-unicode operations + - [ 2622 ] json dumps error (use of AbstractDict) + - [ 2607, 2620 ] Error loading Python DLL (error code 14001) + - [ 2612 ] NPE while trying to load class + - [ 2609 ] PyType.fromClass publication race (discovered in strptime and re) + - [ 2608 ] Encoding problems with non-ascii host name + - [ 2599 ] Cannot handle network paths under Windows + - [ 2600 ] subprocess doesn't have _args_from_interpreter_flags (blocks support for multiprocessing) + - [ 2602 ] NumberFormatException in terminal on OSX 10.12.5 (ncurses related) + + New Features + - Updated JLine to 2.14.5 + +Jython 2.7.1 + same as 2.7.1rc3 + +Jython 2.7.1rc3 + Bugs fixed + - [ 2597 ] PySystemState.sysClosers requires cleanup to prevent memory leak + - [ 2593 ] file.write(obj) raises NullPointerException on type error + - [ 2592 ] Line breaks in exceptions are wrong (characters being backslash-escaped) + +Jython 2.7.1rc2 + Bugs fixed + - [ 2536 ] deadlocks in regrtests due to StackOverflowError in finally block (workaround, still open) + - [ 2348 ] site module does not import if usernames contain non-ascii characters + - [ 2356 ] java.lang.IllegalArgumentException on startup on Windows if username not ASCII + - [ 1839 ] sys.getfilesystemencoding() is None (now utf-8) + - [ 2579 ] Pyc files are not loading for too large modules if path contains __pyclasspath__ + - [ 2570 ] Wrong shebang set for OS X installation of Jython + - [ 2585 ] test_ssl failure due to Netty exception mapping + - [ 2313 ] test_jython_initializer failure on Windows + - [ 2399 ] test_sort failure on Java 8 + - [ 2309 ] test_classpathimporter fails on Windows. + - [ 2318 ] test_zipimport_jy failure on Windows + - [ 2571 ] Error handling in test_codecencodings_tw fails on Java 8 + - [ 2568 ] test_threading intermittent failure + - [ 2559 ] test_marshal fails + - [ 2564 ] test_socket_jy fails on Linux + - [ 2524 ] datetime <-> time conversion incorrect in non UTC times + - [ 2504 ] datetime.date.__tojava__ returns incorrect dates in non-UTC timezones with + negative offset (Jython 2.7.0) + - [ 2500 ] Loading default cacerts on client socket when specifying a default java truststore + unnecessarily searches for more cacerts in the same dir + - [ 2561 ] win32_ver raises exception (breaks test_platform on windows) + - [ 2521 ] Windows installation (all) fails on Windows 10 + - [ 2557 ] ongoing pain with platform detection via os.name and sys.platform + - [ 1996 ] Core slots array out of bounds with multiple inheritance + - [ 2101 ] Diamond-style multiple inheritance fails when using __slots__ on the second branch + + New Features + - Updated Netty to 4.1.11, ASM to 5.2, BouncyCastle to 1.57, Commons Compress to 1.14, + Guava to 22.0, ICU4J to 59.1, JFFI to 1.2.15, JNR-JFFI to 2.1.5, JNR-POSIX to 3.0.41, + JNR-Constants 0.9.9, JLine to 2.14.3, MySQL Connector to 5.1.42, PostgreSQL to 42.1.1 + Note: + You might find it strange that Jython bundles guava-22.0-android.jar rather than guava-22.0.jar. + This is the official way to support Java 7 with Guava > 20.0, also on non-Android platforms. + See https://github.com/google/guava/wiki/Release22#guava-release-220-release-notes. + - There is now support for non-ascii paths in all (home, installation, temporary) + directories, which previously caused failures. sys.getplatformencoding() returns + 'utf-8' as the nominal file-system encoding, irrespective of localization. This may + differ from what CPython reports on the same OS. In Jython a file path presented + as bytes is the UTF-8 encoding of the unicode file path as Java sees it. (See issues + #1839 and #2356.) This matter is unrelated to file.encoding or the console. Jython 2.7.1rc1 Bugs fixed + - [ 2552 ] installing scandir via pip fails (breaks e.g. installing pathlib2 via pip) + - [ 2534 ] os.getlogin() returns a wrong user or returns an exception + - [ 2553 ] sys.getwindowsversion not implemented (breaks pathlib on Windows) + - [ PR55 ] Replace deprecated use of ASCII constant with ascii() + - [ 1777 ] Help getting SymPy working with Jython + - [ 2475 ] Backported python 3 pathlib and pathlib2 do not work b/c of meta class issues + - [ 2551 ] __slots__ in diamond-style causes lay-out conflict (breaks pathlib and sympy) + - [ 2550 ] test_list_jy fails on Java 8 + - [ 2549 ] test_posix fails on Linux + - [ 2548 ] Unicode u'\N{name}' frequently broken, because ucnhash.dat outdated + - [ 2527 ] cStringIO throws IllegalArgumentException with non-ASCII values + - [ 2511 ] Percent operator calls __getattr__('__getitem__') + - [ PR28 ] zipimporter supports multi-byte characters in pathnames + - [ 2228 ] Re-use "makeCompiledFilename" function where possible + - [ 608632 ] __doc__foo should accept java String + - [ 2523 ] defaultdict.__getitem__() does not propagate exceptions raised by calling + default_factory + - [ 2522 ] defaultdict.__getitem__(unhashable) raises KeyError instead of TypeError + - [ 2515 ] typing module doesn't import + - [ 2538 ] Test failures in test_unittest + - [ 2293 ] "java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: + Cannot create PyString with non-byte value" triggered after adding + unicode element with non-ASCII character to sys.path + - [ 2535 ] Building jython standalone manually results in local filesystem paths + showing up in Jython stacktraces + - [ 2533 ] Opcode.java is outdated -> breaks PyBytecode.interpret + - [ 2502 ] Missing OpenFlags enum entry makes Jython clash with JRuby dependency + - [ 2446 ] Support SNI for SSL/TLS client sockets + - [ GH-50 ] Calling Java vararg methods with no arguments fails + - [ 2455 ] Java classes in packages with __init__.py not found + - [ 2481 ] Update urllib2.py from 2.7.11 + - [ 2514 ] Jython Class.__subclasses__() does not match Python output (not in load order) - [ 2413 ] ElementTree.write doesn't close files if used with invalid encoding + - [ 2443 ] java.util.Map derived classes lack iterkeys, itervalues methods - [ 2516 ] _get_open_ssl_key_manager tries to validate that the private and public keys match, and is throwing an SSLError: "key values mismatch" when provided with multiple certs (Root/CA/Cert) @@ -26,9 +268,27 @@ Jython 2.7.1rc1 causes an infinite recursion - [ 2112 ] time.strptime() has different default year in Jython and CPython - [ 1767 ] Rich comparisons - - [ 2443 ] java.util.Map derived classes lack iterkeys, itervalues methods New Features + - Recognize cpython_cmd property to automatically build CPython bytecode for oversized + functions (e.g. jython -J-Dcpython_cmd=python). This is especially convenient when + installing things like SymPy via pip; it would frequently prompt you to provide yet + another pyc-file. Now just run: pip install --global-option="-J-Dcpython_cmd=python" sympy + - SymPy is now workable. (However it runs somewhat slow; some profiling will be required.) + - Updated ucnhash to support name lookup for Unicode 9.0 (like in u'\N{name}'). + - Jython doc-entries in Java-code (__doc__foo) now accept anything that implements + java.lang.CharSequence (PyString implements CharSequence now as well). + This allows Jython-friendly Java-code without PyString-induced dependency on Jython. + - Provided a painless way to deal with long-standing Issue 527524 - "Cannot compile to use + methods exceeding JVM size restrictions": If a CPython 2.7 bytecode-file (.pyc) exists, + Jython automatically uses that bytecode to represent oversized functions and methods, + while methods with proper size are still compiled to JVM bytecode. + The crucial bytecode sections from the pyc-file are embedded seamlessly into the created + class-file, so you wouldn't have to distribute the pyc-file at all. + Current implementation of this feature is provisional and might change in future versions. + Issue 527524 was still not listed as solved, because Jython cannot yet create the pyc-file + by itself. + - Support for CPython bytecode (.pyc-files) was updated to Python 2.7 bytecode (from 2.5). - Buffer API changes allow java.nio.ByteBuffer to provide the storage when a PyBuffer is exported. This is to support CPython extensions via JyNI, but has other uses too (including access to direct memory buffers from Python). There is no change at the diff --git a/README.md b/README.md new file mode 100644 index 000000000..be9283e26 --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# Jython: Python for the Java Platform +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.python/jython-standalone/badge.svg)](https://search.maven.org/artifact/org.python/jython-standalone/) +[![Javadocs](https://www.javadoc.io/badge/org.python/jython-standalone.svg)](https://www.javadoc.io/doc/org.python/jython-standalone) + +This is the development repository of Jython, +the implementation of Python 2.7 in Java. +Along with good (not perfect!) language +and runtime compatibility with CPython 2.7, +Jython 2.7 provides substantial support of the Python ecosystem. +This includes built-in support of *pip/setuptools* +(you can use `bin/pip` if the targets do not include `C` extensions) +and a native launcher for Windows (`bin/jython.exe`) +that works essentially as the `python` command. + +Jim Baker presented a talk at PyCon 2015 about Jython 2.7, +including demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo + +See [ACKNOWLEDGMENTS](ACKNOWLEDGMENTS) for details about Jython's copyright, +license, contributors, and mailing lists. +Consult [NEWS](NEWS) for detailed release notes, including bugs fixed, +backwards breaking changes, and new features. +We sincerely thank all who contribute to Jython, by bug reports, patches, +pull requests, documentation changes and e-mail discussions. + +## How to build Jython + +The project uses Mercurial for version-control, +and the master repository is at https://hg.python.org/jython/, +while the repository on GitHub is just a mirror of that. +You may clone either repository to create a buildable copy of the latest state +of the Jython source. + +### Build using `ant` for development + +Jython is normally built using `ant`. +It is necessary to have Ant and at least a Java 7 SDK on the path. +To build Jython development use, we generally use the command: +``` +ant +``` +This leaves an executable in `dist/bin` +that you may run from the check-out root with: +``` +dist/bin/jython +``` +Other `ant` targets exist, notably `clean`, and `jar`. + +You can test your build of Jython (by running the regression tests), +with the command: +``` +dist/bin/jython -m test.regrtest -e -m regrtest_memo.txt +``` + +### Build an installer using `ant` + +If you want to install a snapshot build of Jython, use the command: +``` +ant installer +``` +This will leave you with a snapshot installer JAR in `dist`, +that you can run with: +``` +java -jar jython-installer.jar +``` +for the graphical installer, or: +``` +java -jar jython-installer.jar --console +``` +For the console version. (A `--help` option gives you the full story.) + +### Build a JAR using Gradle + +Experimentally, we have a Gradle build that results in a family of JARs, +and a POM. +This is intended to provide the Jython core in a form that Gradle and Maven +users can consume as a dependency. +Invoke this with: +``` +PS> .\gradlew publish +``` +and a JAR and POM are delivered to ` .build2\repo` + +Whereas the JARs delivered by the installer are somewhat "fat", +embedding certain dependencies in shaded (renamed) form, +the JARs from the Gradle build are "spare" +and cite their dependencies externally through a POM. +The project would like to know if this is being done suitably +for downstream use. diff --git a/README.txt b/README.txt index 8ef905a11..68d5b758e 100644 --- a/README.txt +++ b/README.txt @@ -1,38 +1,42 @@ Jython: Python for the Java Platform +------------------------------------ -Welcome to Jython 2.7.1 beta 3! +Welcome to Jython @jython.version@. +@snapshot.banner@ +This is @readme.release@ release of version @jython.version.short@ of Jython. -This is the third beta release of the 2.7.1 version of Jython. Along with -language and runtime compatibility with CPython 2.7.1, Jython 2.7 provides -substantial support of the Python ecosystem. This includes built-in support of -pip/setuptools (you can use with bin/pip) and a native launcher for Windows -(bin/jython.exe), with the implication that you can finally install Jython -scripts on Windows. +Along with language and runtime compatibility with CPython 2.7, Jython 2.7 +provides substantial support of the Python ecosystem. This includes built-in +support of pip/setuptools (you can use with bin/pip) and a native launcher +for Windows (bin/jython.exe). -* Note that if you have JYTHON_HOME set, you should unset it to avoid problems -with the installer and pip/setuptools. +Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including demos +of new features: https://www.youtube.com/watch?v=hLm3garVQFo -Jim Baker presented a talk at PyCon 2015 about Jython 2.7, including -demos of new features: https://www.youtube.com/watch?v=hLm3garVQFo +This release was compiled on @os.name@ using @java.vendor@ Java +version @java.version@ and requires a minimum of Java @jdk.target.version@ to run. -The release was compiled on OSX using JDK 7 and requires a minimum of -Java 7 to run. +See ACKNOWLEDGMENTS for details about Jython's copyright, license, +contributors, and mailing lists; and NEWS for detailed release notes, +including bugs fixed, backwards breaking changes, and new features. -Please try this release out and report any bugs at http://bugs.jython.org -You can test your installation of Jython (not the standalone JAR) by running -the regression tests, with the command: +The developers extend their thanks to all who contributed to this release +of Jython, through bug reports, patches, pull requests, documentation +changes, email and conversation in any media. We are grateful to the PSF for +continuing practical help and support to the project. -jython -m test.regrtest -e -m regrtest_memo.txt +Testing +------- +You can test your installation of Jython (not the standalone jar) by +running the regression tests, with the command: -For Windows, there is a simple script to do this: jython_regrtest.bat. In -either case, the memo file regrtest_memo.txt will be useful in the bug report -if you see test failures. The regression tests can take about half an hour. +jython -m test.regrtest -e + +The regression tests can take about fifty minutes. At the time of writing, +these tests are known to fail (spuriously) on an installed Jython: + test___all__ + test_java_visibility + test_jy_internals + test_ssl_jy +Please report reproducible failures at http://bugs.jython.org . -Please see ACKNOWLEDGMENTS for details about Jython's copyright, -license, contributors, and mailing lists; and NEWS for detailed -release notes, including bugs fixed, backwards breaking changes, and -new features. Thanks go to Amobee (http://www.amobee.com/) for -sponsoring this release. We also deeply thank all who contribute to -Jython, including - but not limited to - bug reports, patches, pull -requests, documentation changes, support emails, and fantastic -conversation on Freenode at #jython. diff --git a/b/.idea/libraries/extlibs.xml b/b/.idea/libraries/extlibs.xml index c6b6bcfbd..2e5e50203 100644 --- a/b/.idea/libraries/extlibs.xml +++ b/b/.idea/libraries/extlibs.xml @@ -1,45 +1,56 @@ - - - - - - - - + + + + + + + + + + + + + + - - - - + - - - - - - - - - - - - - + - - - + + + - - - + - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/bugtests/README.txt b/bugtests/README.txt index c2b087c10..7e86be369 100644 --- a/bugtests/README.txt +++ b/bugtests/README.txt @@ -2,6 +2,14 @@ This directory contains small tests that attempt to ensure that old fixed bugs do not reappear. +These tests are not actively maintained and while many pass, others have been +broken by changes in the main codebase and now fail for what might be spurious +reasons. + +As the regression tests have grown, the need for these has largely ceased. +It is likely these tests will be removed eventually. + + Running ======= diff --git a/bugtests/support.py b/bugtests/support.py index 30c87a35b..04a2669c2 100644 --- a/bugtests/support.py +++ b/bugtests/support.py @@ -84,7 +84,7 @@ def compileJava(src, **kw): cmd = "%s/bin/javac -classpath %s %s" % (cfg.java_home, classpath, src) elif WIN: src = src.replace("/", "\\") - cmd = 'cmd /C "%s/bin/javac.exe -classpath %s %s"' % (cfg.java_home, classpath, src) + cmd = 'cmd /C "%s/bin/javac.exe" -classpath %s %s' % (cfg.java_home, classpath, src) return execCmd(cmd, kw) def runJava(cls, **kw): @@ -98,7 +98,7 @@ def runJava(cls, **kw): if UNIX: cmd = ['/bin/sh', '-c', "%s/bin/java -classpath %s %s %s" % (cfg.java_home, classpath, defs, cls)] elif WIN: - cmd = 'cmd /C "%s/bin/java.exe -classpath %s %s %s"' % (cfg.java_home, classpath, defs, cls) + cmd = 'cmd /C "%s/bin/java.exe" -classpath %s %s %s' % (cfg.java_home, classpath, defs, cls) return execCmd(cmd, kw) def runJavaJar(jar, *args, **kw): @@ -106,7 +106,7 @@ def runJavaJar(jar, *args, **kw): if UNIX: cmd = ['/bin/sh', '-c', "%s/bin/java -jar %s %s" % (cfg.java_home, jar, argString)] elif WIN: - cmd = 'cmd /C "%s/bin/java.exe -jar %s %s"' % (cfg.java_home, jar, argString) + cmd = 'cmd /C "%s/bin/java.exe" -jar %s %s' % (cfg.java_home, jar, argString) return execCmd(cmd, kw) def runJython(cls, **kw): @@ -119,7 +119,7 @@ def runJython(cls, **kw): if UNIX: cmd = "%s/bin/java -classpath %s %s -Dpython.home=%s org.python.util.jython %s" % (cfg.java_home, classpath, javaargs, cfg.jython_home, cls) elif WIN: - cmd = 'cmd /C "%s/bin/java.exe -classpath %s %s -Dpython.home=%s org.python.util.jython %s"' % (cfg.java_home, classpath, javaargs, cfg.jython_home, cls) + cmd = 'cmd /C "%s/bin/java.exe" -classpath %s %s -Dpython.home=%s org.python.util.jython %s' % (cfg.java_home, classpath, javaargs, cfg.jython_home, cls) return execCmd(cmd, kw) def compileJPythonc(*files, **kw): @@ -148,12 +148,12 @@ def compileJPythonc(*files, **kw): classpath = cfg.classpath if "classpath" in kw: classpath = os.pathsep.join([cfg.classpath, kw["classpath"]]) - + jythonc = "%s/Tools/jythonc/jythonc.py %s" % (cfg.jython_home, cmd) if UNIX: cmd = "%s/bin/java -classpath %s -Dpython.home=%s org.python.util.jython %s" % (cfg.java_home, classpath, cfg.jython_home, jythonc) elif WIN: - cmd = 'cmd /C "%s/bin/java.exe -classpath \"%s\" -Dpython.home=%s org.python.util.jython %s"' % (cfg.java_home, classpath, cfg.jython_home, jythonc) + cmd = 'cmd /C "%s/bin/java.exe" -classpath "%s" -Dpython.home=%s org.python.util.jython %s' % (cfg.java_home, classpath, cfg.jython_home, jythonc) return execCmd(cmd, kw) def grep(file, text, count=0): @@ -173,7 +173,7 @@ def grep(file, text, count=0): class JarPacker: __doc__ = """helper class to pack stuff into a jar file - the terms 'file' and 'dir' mean java.io.File here """ - + def __init__(self, jarFile, bufsize=1024): self._jarFile = jarFile self._bufsize = bufsize @@ -186,11 +186,11 @@ def close(self): def addManifestFile(self, manifestFile): __doc__ = """only one manifest file can be added""" self.addManifest(Manifest(FileInputStream(manifestFile))) - + def addManifest(self, manifest): if not self._manifest: self._manifest = manifest - + def addFile(self, file, parentDirName=None): buffer = jarray.zeros(self._bufsize, 'b') inputStream = FileInputStream(file) @@ -204,7 +204,7 @@ def addFile(self, file, parentDirName=None): read = inputStream.read(buffer) self.getJarOutputStream().closeEntry() inputStream.close() - + def addDirectory(self, dir, parentDirName=None): if not dir.isDirectory(): return @@ -221,7 +221,7 @@ def addDirectory(self, dir, parentDirName=None): else: newParentDirName = dir.getName() self.addDirectory(currentFile, newParentDirName) - + def addJarFile(self, jarFile): __doc__ = """if you want to add a .jar file with a MANIFEST, add it first""" jarJarFile = JarFile(jarFile) diff --git a/bugtests/test236.py b/bugtests/test236.py deleted file mode 100644 index ac76e8114..000000000 --- a/bugtests/test236.py +++ /dev/null @@ -1,23 +0,0 @@ - -import support, os - -support.compileJava("classes/test236j1.java", force=1) -os.remove("classes/test236j2.class") - -onimport = 1 - -import java -try: - import test236j1 - onimport = 0 - test236j1() -except ImportError: - raise support.TestError, "Should not raise a simple ImportError" -except java.lang.NoClassDefFoundError: - if not onimport: - raise support.TestWarning, "import itself does not imply class initialization" -else: - raise support.TestError, "Should raise some exception" - - - diff --git a/bugtests/test401.py b/bugtests/test401.py deleted file mode 100644 index 702ade6e6..000000000 --- a/bugtests/test401.py +++ /dev/null @@ -1,18 +0,0 @@ -# -# Test for bug 1758838 -# -# execfile() should not throw a NullPointerException -# -# The error only shows up in interactive interpretation (type "single" for the compilation). -# But we cannot use InteractiveInterpreter here since it catches all Exceptions, -# therefore we do the compilation 'by hand'. -# - -from org.python.core import Py -from org.python.core import PySystemState -from org.python.util import PythonInterpreter - -PySystemState.initialize() -interp = PythonInterpreter() -code = Py.compile_command_flags("execfile('test401/to_be_executed.py')", "", "single", None, 1) -interp.exec(code) diff --git a/bugtests/test401/to_be_executed.py b/bugtests/test401/to_be_executed.py deleted file mode 100644 index 3ab36196c..000000000 --- a/bugtests/test401/to_be_executed.py +++ /dev/null @@ -1,4 +0,0 @@ -# the contents of this file are not important for bug 1758838 - -class TestBug1758838: - pass diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..a33178778 --- /dev/null +++ b/build.gradle @@ -0,0 +1,908 @@ +/* + * Gradle build for Jython. See also settings.gradle. + * + * This is an attempt to build a distributable JAR using Gradle that could be + * cited as a dependency by other Gradle or Maven projects, when they use the + * Jython interpreter from Java (under JSR-223 or directly). + * + * At present, the build is additional to the Ant build that remains the + * primary and reliable support for development, for test, and to build the + * Jython installers. + * + * The delivered jar should contain only Jython project material (Java classes + * and the Python library) while the many JARs Jython depends on will be cited + * in the accompanying metadata as dependencies. + * + * The Jython source structure does not follow the standard convention for + * Gradle. This script deals with that without changing it, but it uses a build + * directory (build2) entirely separate from Ant's, in which generated and + * compiled material is posted conformant with Gradle conventions. This means + * that the later tasks Gradle provides (test and jar) do not need so much + * customisation. + */ + +plugins { + id 'java-library' + id 'antlr' + id 'maven-publish' +} + +import java.text.SimpleDateFormat + +// ---------------- Determine the version of Jython ---------------------------- + +/* + * This one string will be used to name the generated JAR and version-stamp the + * application. It should be all you have to edit to version a release built + * here. But of course you have to do it the hard way too (see build.xml) as + * long as Ant is also used. + * + * The convention here is that you specify the version of the *next* release. If + * there are files not checked in, extra files (not of types hg ignores), or the + * changeset is not tagged correspondingly, the build will add "-SNAPSHOT" to + * the effective version. + */ +// Versions are specified in this grammar: +// . ( . )? ( )? ( - )? + +version = '2.7.3a1' + +// Valid examples (please preserve in comments): +//version = '2.7.2a2' +//version = '2.7.2b2-DEV' +//version = '2.7.2b1' +//version = '2.7.2rc1' +//version = '2.7.2' + +group = 'org.python' + + +// ---------------- Miscellaneous configuration -------------------------------- + +/* + * We support Java 8 onwards officially, up to v2.7.2, but retain the option of + * compiling for Java 7 (in v2.7.2) by maintaining compatibility in the code + * base and in the choice of JARs. + */ +sourceCompatibility = '1.7' // Make both 1.8 after 2.7.2 released +targetCompatibility = '1.8' + +project.compileJava.options.debug = true + + +// Separate the Gradle build from that of Ant +buildDir = file('build2') +ext { + buildDate = new Date() + /* + * The directory structure supporting the build has separate locations for + * several intermediate stages. + */ + // Java source generated by ANTLR + antlrGenDir = "$buildDir/gensrc/org/python/antlr" + // Intermediate locations for compiled classes + unexposedDir = "$buildDir/unexposed" + exposedDir = "$buildDir/exposed" + // The standard library may safely be assembled in-place as a resource + pythonLibDir = "$buildDir/python/Lib/" + buildLibDir = "$buildDir/resources/main/Lib/" + buildTestLibDir = "$buildDir/resources/test/Lib/" + compiledLibDir = "$buildDir/resources/main/Lib/" + compiledTestLibDir = "$buildDir/resources/test/Lib/" +} + + +repositories { + // Jython is distributed through Maven Central. Get our dependencies there too. + mavenCentral() +} + +sourceSets { + + main { // Non-standard locations must be specified explicitly + + antlr { + srcDirs = ['grammar'] + exclude 'Base.g' // Not used (and produces errors) + } + + java { + srcDirs = ['src', project.ext.antlrGenDir] + // Reference to proprietary libraries not supplied + exclude 'com/ziclix/python/sql/handler/InformixDataHandler.java' + exclude 'com/ziclix/python/sql/handler/OracleDataHandler.java' + } + + resources { + // Resources in project root, but this invites an explosion. + // ... so claim no sources: + srcDirs = [] + // and fix it in task processResources + } + } + + test { // Non-standard locations must be specified explicitly + + java { + srcDirs = ['tests/java'] + // Reference to proprietary libraries not supplied + exclude 'com/ziclix/python/sql/**' + } + } +} + +dependencies { + /* + * Must these correspond exactly with the external libraries (JARs) + * mentioned in the Ant build.xml? Or is some form of dynamic version + * better for downstream? + * + * Note that an application may specify a later version. Gradle will + * choose the latest required. + */ + + // Using a version available from repo (not 'extlibs/servlet-api-2.5' as in build.xml) + implementation 'javax.servlet:javax.servlet-api:3.1.0' + + /* + * These seem to be unnecessary while the proprietary database support is + * not bundled with Jython. Applications needing them can cite these or a + * version they prefer. + */ + //implementation 'mysql:mysql-connector-java:5.1.42' + //implementation 'org.postgresql:postgresql:42.1.1.jre7' + + // pin to Antlr 3 until we upgrade parsing + antlr 'org.antlr:antlr:3.5.2' + implementation 'org.antlr:antlr-runtime:3.5.2' + + implementation 'org.apache.commons:commons-compress:1.19' + + implementation 'org.bouncycastle:bcpkix-jdk15on:1.62' + implementation 'org.bouncycastle:bcprov-jdk15on:1.62' + + implementation 'org.ow2.asm:asm:7.1' + implementation 'org.ow2.asm:asm-commons:7.1' + implementation 'org.ow2.asm:asm-util:7.1' + + // The Android Guava and "failureaccess" are necessary to support Java 7. + implementation 'com.google.guava:guava:28.0-android' + implementation 'com.google.guava:failureaccess:1.0.1' + // Swap for regular Guava at Java 8. + + implementation 'com.ibm.icu:icu4j:59.1' + + implementation 'com.carrotsearch:java-sizeof:0.0.5' + + implementation 'com.github.jnr:jffi:1.2.20' + implementation 'com.github.jnr:jnr-netdb:1.1.6' + implementation 'com.github.jnr:jnr-ffi:2.1.10' + implementation 'com.github.jnr:jnr-posix:3.0.50' + implementation 'com.github.jnr:jnr-constants:0.9.12' + + implementation 'jline:jline:2.14.5' + + implementation 'io.netty:netty-buffer:4.1.45.Final' + implementation 'io.netty:netty-codec:4.1.45.Final' + implementation 'io.netty:netty-common:4.1.45.Final' + implementation 'io.netty:netty-handler:4.1.45.Final' + implementation 'io.netty:netty-resolver:4.1.45.Final' + implementation 'io.netty:netty-transport:4.1.45.Final' + + // Used implicitly in the Ant build, must be explicit here + implementation 'org.apache.ant:ant:1.9.7' + + // Pin to 4.10 until dependency on hamcrest classes resolved. + testImplementation 'junit:junit:4.10' +} + + +// ---------------- Resource Processing ---------------------------------------- + +/* + * Jython brings several files we could treat as resources, but they do not sit + * in the Gradle-conventional 'main/resources' directory, rather are in the + * project root or rub shoulders with the java source. Pick them individually. + * + * Several tasks defined below declare that processResources depends on them, + * with the objective that at the end of processResources all generated + * resources and the stdlib (but not the compiled stdlib) should be in place + * in $buildDir/resources/main. + */ +processResources { + from(file('.')) { + include 'LICENSE.txt' + } + from(file('src')) { + include 'META-INF/**' + include 'org/python/modules/ucnhash.dat' + } +} + +// ---------------- ANTLR Task ------------------------------------------------- + +generateGrammarSource { + maxHeapSize = "512m" + outputDirectory = file(antlrGenDir) +} + +// ---------------- compleJava Task -------------------------------------------- + +compileJava { + // Divert compiled classes to intermediate location pre-exposure. + destinationDir = file(unexposedDir) +} + +// ---------------- Expose Task ------------------------------------------------ + +/* + * The exposer operates between the output of compileJava (unexposed directory) + * and a second intermediate location (exposed directory). These two the + * mergeExposed task will finally combine in the Gradle-standard classes + * directory used as input by the jar task. + */ +configurations { + expose.extendsFrom(implementation) +} + +dependencies { + // The expose (Ant) task depends on classes compiled to here: + expose files(unexposedDir) +} + +// A (Gradle) task to run the Ant task 'expose'. +task expose (group: 'Custom', dependsOn: compileJava) { + + description = 'Expose Java types to Python using their annotations.' + + // Allow Gradle to infer the need to regenreate the outputs + inputs.files(fileTree("${project.ext.unexposedDir}/org/python")) + outputs.dir(project.ext.exposedDir) + + doLast { + /* + * Define an Ant task called 'expose' in the project's AntBuilder. + * We can't define it until ExposeTask has been compiled. + */ + ant.taskdef( + name: 'expose', + classname: 'org.python.expose.generate.ExposeTask', + classpath: configurations.expose.asPath + ) + + // Use the Gradle-conventional directory structure (not the legacy one). + ant.expose( + srcdir: file(project.ext.unexposedDir), + destdir: mkdir(file(project.ext.exposedDir)), + includesfile: file('CoreExposed.includes') + ) + } +} + +// Task to merge the exposed and unexposed classes +task mergeExposed(group: 'Custom', type:Copy, dependsOn: expose) { + description = 'Copy exposed Java types to classes.' + // Exposed version will take precedence + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from file(exposedDir) + from file(unexposedDir) + into sourceSets.main.output.classesDirs.singleFile +} + +// Attach to the classes task the placing of all compiled and exposed classes. +classes.dependsOn(mergeExposed) + + +// ---------------- Version-related file generation ---------------------------- + +/* + * Write the information that org.python.Version reads from + * org/python/version.properties in the class file structure. The inputs to + * this are: information from Mercurial (hg command required); project.version; + * and project.ext.buildDate. The task works quite hard to decode + * project.version, which must have the correct form, to deduce whether you + * really intend this to be a release. If anything comes after the release + * number, typically it's a '+' sign, the version becomes a snapshot. + */ +task generateVersionInfo( + type: WriteProperties, + description: 'Write the version information as properties') { + + outputFile = file("${processResources.destinationDir}/org/python/version.properties") + comment = ' Jython version information (from build.gradle)' + + // Create the properties when the task runs. But do it before the write! + doFirst { + // Query Mercurial for version and tagging. + String hgOutput = 'hg identify -ibt'.execute().text + hgOutput = hgOutput.split('\n', 2)[0] + + // (+)? + String[] parts = hgOutput.split(/\s+/, 3) + if (parts.length != 3) { + throw new IllegalArgumentException( + "Cannot split Mercurial output '$hgOutput' into 3") + } + def (ident, branch, tag) = parts + property('jython.build.hg_branch', branch) + property('jython.build.hg_tag', tag) + property('jython.build.hg_version', ident) + + /* + * Decompose the version string into elements for Jython to access as + * properties. (The Ant build.xml requires them to be set in parts, but + * we can work it out from project.version.) + */ + // .(.)()?(+|-)? + def versionRegex = /(\d+)\.(\d+)(\.(\d+))?((a|b|rc)(\d+))?(\+|-(\w+))?/ + def versionMatcher = project.version =~ versionRegex + if (versionMatcher.count != 1) { + throw new IllegalArgumentException( + "Cannot parse project version string '${project.version}'") + } + // In principle it could match more than once: take the leftmost + def versionResult = versionMatcher[0] + + // . means ..0 + String major = versionResult[1] + String minor = versionResult[2] + String micro = versionResult[3] ? versionResult[4] : '0' + + // Convert the optional to numbers + int level = 0, serial = 0 + if (versionResult[5]) { + // This is some kind of pre-final release (unless snapshot) + serial = versionResult[7] as int + switch (versionResult[6]) { + case 'a': level = 0xa; break // ALPHA release + case 'b': level = 0xb; break // BETA release + case 'rc': level = 0xc; break // release candidate + } + } else { + // Not marked as a/b/rc so ostensibly a final release. + level = 0xf + } + + // Convert optional +|- to -DEV or -SNAPSHOT suffix or empty string + String snapshotSuffix = versionResult[8]; + if (snapshotSuffix == '+') { + snapshotSuffix = "-SNAPSHOT" + } + + /* + * Work out if it looks like a release, or adjust project.version. This logic prevents us + * releasing from a polluted repo (similar to logic in the Ant build.xml). + */ + def L = [0:'', 10:'a', 11:'b', 12:'rc', 15:''] + String release = "$major.$minor.$micro${L[level]}${serial?:''}" + + if (snapshotSuffix == null) { + // The version is named correctly for a release. Make safety checks on the repo. + String expectTag = "v$release" + String message = null; + if (ident.endsWith('+')) { + message = 'Version-controlled files have been edited since the last commit' + } else if (tag != expectTag) { + message = "Change set $ident is not tagged $expectTag." + } else { + // Query Mercurial for status: non-empty if uncontrolled (unignored) files. + String hgStatus = 'hg status'.execute().text + if (hgStatus.trim().length() > 0) { + message = 'Workspace contains uncontrolled files' + } + } + // If a message was set for any reason, fall back to a snapshot. + if (message == null) { + // Repository state is good for a full build. + snapshotSuffix = '' + } else { + // Some reason found not to build the release. + println "$message - build is a snapshot." + snapshotSuffix = '-SNAPSHOT' + } + } + + // Rebuild the version with the snapshot suffix, even if not given originally. + project.version = release + snapshotSuffix + println "This build is for v${project.version}." + + property('jython.version', project.version) + property('jython.major_version', major) + property('jython.minor_version', minor) + property('jython.micro_version', micro) + property('jython.release_level', level) + property('jython.release_serial', serial) + + /* + * Time-stamp the build. In the time part, the ':' gets escaped to + * '\:', consistent with Properties.store(), unlike the Ant build. + */ + property('jython.build.time', + (new SimpleDateFormat('HH:mm:ss')) + .format(project.ext.buildDate)) + property('jython.build.date', + (new SimpleDateFormat('MMM d yyyy')) + .format(project.ext.buildDate)) + } +} + +// Attach this task to processResources +processResources.dependsOn(generateVersionInfo) + + +// ---------------- Copy Python Library ---------------------------------------- + +/* + * The default behaviour of the Java plug-in is to make a JAR of the classes in + * the "main" source set. We need a more complex assembly that provides users + * with exposed classes instead of their plain counterparts, and also various + * configuration files and the Python library. + * + * These copies include the tests, so we can test things :), but a subsequent + * JarTask of the build should exclude them as necessary. (Not yet implemented.) + */ + +ext { + libPython = 'lib-python/2.7' + libJython = 'Lib' + libTestSpecs = [ + 'distutils/tests/', + 'email/test/', + 'json/tests/', + 'lib2to3/tests/', + 'unittest/test/', + 'test/' + ] +} + +/* + * Copy the Python standard library. We take this from a distribution of + * CPython, but take only the files specified in CPythonLib.includes. + * The Jython version of the standard library will be copied to the same place. + * Files from the Jython library having the same name (relative path) as one + * in CPythonLib.includes thereby take precedence. + */ +task mergePythonLib( + type: Copy, + description: 'Merge lib-python and Jython Lib') { + + // There might be a way using a collection of File rather than actual copy. + into pythonLibDir + + // Copy Jython Lib, with precedence over CPython files of the same name + duplicatesStrategy = DuplicatesStrategy.INCLUDE + from libJython + exclude '**/*.class' + + // Allow Gradle to infer the need to regenerate the outputs + inputs.dir libJython + inputs.dir libPython + inputs.file file('CPythonLib.includes') + + doFirst { + // Select the CPython stdlib files by making a list. + def cPythonLibIncludes = [] + // Read list from CPythonLib.includes, stripping comments and spaces. + file('CPythonLib.includes').eachLine { line -> + def trimmed = line.split('#', 2)[0].trim() + if (trimmed.length() > 0) { + cPythonLibIncludes << trimmed + } + } + // Copy the subset as specified by the list + project.copy { + into pythonLibDir + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from libPython + include cPythonLibIncludes + exclude '**/*.pyc', '**/*.pyd' + } + } +} + +/* + * Copy from the merge location into the main resources, excluding material + * only needed for tests. + */ +task copyLib( + type: Copy, + dependsOn: mergePythonLib, + description: 'Copy merged Python library (main excluding tests)') { + into buildLibDir + from pythonLibDir + exclude '**/*.pyc', '**/*.pyd', '**/*.class' + // Exclude tests and test material + exclude libTestSpecs +} + +// Attach this task to processResources +processResources.dependsOn(copyLib) + +/* + * Copy from the merge location into the test resopurces, including only + * that extra material needed for tests. + */ +task copyTestLib( + type: Copy, + dependsOn: mergePythonLib, + description: 'Copy merged Python library (tests only)') { + into buildTestLibDir + from pythonLibDir + exclude '**/*.pyd', '**/*.class' // test material includes .pyc files + // Include only tests and test material + include libTestSpecs +} + +// Attach this task to processResources +processTestResources.dependsOn(copyTestLib) + + +// ---------------- Jython-Compile Python -------------------------------------- + +/* + * Compile the Python modules to .class files for the JAR. Whereas Jython runs + * happily with a concrete Lib folder, creating and caching the .class files, + * when Jython is supplied as a JAR, we prefer to compile the class files once + * in advance. + */ + +configurations { + pycompile.extendsFrom(implementation) +} + +dependencies { + // Jython as built so far should be on the path of the jycompile (Ant) task + pycompile files("$buildDir/classes/java/main") + pycompile files("$buildDir/resources/main") +} + +// A (Gradle) task to run the Ant task 'jycompile' (not pycompile). +task pycompile( + group: 'Custom', + description: 'Compile the Python modules to .class files for the JAR') { + + // Compiler depends on rest of Jython being fully assembled in 'classes' + dependsOn classes + // Note that classes depends on processResources (Java plug-in). + + // Allow Gradle to infer the need to regenerate the outputs + inputs.dir project.ext.buildLibDir + outputs.dir project.ext.compiledLibDir + + doFirst { + /* + * Define an Ant task called 'jycompile' in the project's AntBuilder. + * We can't define it until JythoncAntTask has been compiled, so this + * must happen during the execution of the task (early). + */ + ant.taskdef( + name: 'jycompile', + classname: 'org.python.util.JycompileAntTask', + classpath: configurations.pycompile.asPath + ) + } + + doLast { + /* + * Now use the 'jycompile' Ant task to compile the Python source we + * supply to users. The exclusions have been copied from build.xml, + * and also this comment: + + */ + def exclusions = ['test/**', 'lib2to3/tests/**', + 'lib2to3/tests/data/myfixes/**'] + ant.jycompile( + srcdir: project.ext.buildLibDir, + destdir: project.ext.compiledLibDir, + excludes: exclusions.join(',') // Yes, it's that way round :o + ) + } +} + + +// ---------------- Building the JARs ------------------------------------------ + +/* + * The default behaviour of the Java plug-in is to make a JAR of the classes in + * the "main" source set and its resources. Having carefully substituted/added + * exposed classes in the assembled classes directory, and having prepared the + * (compiled) stdlib as a resource, this is close to what we need, with a few + * adjustments as noted. + */ +jar { + + // Ensure that compiled stdlib is part of the resources to JAR. + dependsOn pycompile + + // It is important for import that X$py.class be newer than X.py + preserveFileTimestamps = true + + // We don't JAR the expose tool itself + exclude 'org/python/expose/generate/**' + + // Build a custom manifest + manifest { + // These attribute values are based on inspecting the ant build + attributes ([ + 'Main-Class': 'org.python.util.jython', + 'Built-By': 'build.gradle', + ]) + + attributes( [ // Build-Info section + 'version': project.version, + 'build-compiler': 'modern', + 'jdk-target-version': project.targetCompatibility, + 'debug': compileJava.options.debug, + 'informix': false, + 'oracle': false + ], 'Build-Info' ) + } +} + +/* + * This is a task complementary to the jar task, taking just the test material. + * This is not published via the main repositories because it counts as a + * distinct artefact with its own POM. + */ +// XXX Consider instead a multi-project build with one artefact per sub-project. +task testJar(type: Jar) { + classifier = 'tests' + + from sourceSets.test.output + // We don't JAR the expose tool, so we don't JAR the tests + exclude 'org/python/expose/generate/**' + + // Build a custom manifest + manifest { + // These attribute values are based on inspecting the ant build + attributes ([ + //'Main-Class': 'org.python.util.jython', + 'Built-By': 'build.gradle', + ]) + + attributes( [ // Build-Info section + 'version': project.version, + 'build-compiler': 'modern', + 'jdk-target-version': project.targetCompatibility, + 'debug': compileTestJava.options.debug + ], 'Build-Info' ) + } +} + + +// ---------------- Documentation ---------------------------------------------- + +/* + * The JavaDoc, anyway. + */ +javadoc { + options.encoding = 'UTF-8' + source = fileTree(dir: 'src', include: '**/*.java') +} + +// ---------------- Publication ------------------------------------------------ + +/* + * Post the JAR we built to a public repository. We provide secondary -source + * and -javadoc JARs too (supporting 'main'). + * + * How do we test the artifact actually published is correct? The 'test' task + * tests Jython laid out in the build directory, not the JAR we propose to + * distribute. + * + * Maybe have a second JAR that contains the additional material necessary to + * run integration tests (regression tests and others). + */ + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allJava +} + +task javadocJar(type: Jar, dependsOn: javadoc) { + classifier = 'javadoc' + from javadoc.destinationDir +} + +publishing { + + publications { + // The production JAR we expect to be cited as a dependency by users + main(MavenPublication) { + + from components.java + + // Also provide the source. + artifact sourcesJar + // Also provide the docs. (Some javadoc errors currently.) + artifact javadocJar + + pom { + // Same description as in ~/maven/pom-template + name = 'Jython' + description = + 'Jython is an implementation of the high-level, dynamic, object-oriented\n' + + 'language Python written in 100% Pure Java, and seamlessly integrated with\n' + + 'the Java platform. It thus allows you to run Python on any Java platform.' + url = 'https://www.jython.org/' + + // We use the PSF 2.0, but only most recently, but actually a bundle. + licenses { + license { + name = 'Jython Software License' + // Not actually the license URL, but linked from here. + url = 'https://www.jython.org/' + distribution = 'repo' + } + } + + // Point to hg repositories hosetd by PSF (up to 2.7.2, anyway). + scm { + connection = 'scm:hg:https://hg.python.org/jython' + developerConnection = 'scm:hg:ssh://hg@hg.python.org/jython' + url = 'https://hg.python.org/jython' + } + + // Could list us all, but why not just the list for now? + developers { + developer { + id = 'jython' + name = 'Jython Developers' + email = 'jython-dev@lists.sourceforge.net' + } + } + } + } + } + + repositories { + // Staging area where ant -f maven/build.xml will look. + maven { + name = 'stagingRepo' + url = "file://${buildDir}/stagingRepo" + } + } +} + +// Ensure version computation/branding precedes any publication we use. +publish.dependsOn(generateVersionInfo) + +/* FIXME: Depending on publishMainPublicationToMavenLocal does not work, + because it does not exist when evaluating this line. Is this the deferred + configuration removed in Gradle 5.0? Failsd on POM version mismatch if main + publish task not run before publishMainPublicationToMavenLocal. +*/ +//publishMainPublicationToMavenLocal.dependsOn(generateVersionInfo) + + +// ---------------- Java unit tests -------------------------------------------- + +ext { + //distDir = relativePath("$buildDir/assembly") + testSourceDir = relativePath('tests/java') +} + + +dependencies { + // Put the exposed classes on the path of the test tasks + testImplementation files(expose) +} + +// Ensure exposed classes are ahead of standard path +sourceSets.test { + compileClasspath = files(expose.outputs) + compileClasspath + runtimeClasspath = files(expose.outputs) + runtimeClasspath + // println "runtimeClasspath = ${runtimeClasspath.asPath}" +} + +compileTestJava { + dependsOn expose + options.debug = project.compileJava.options.debug +} + +test { + + dependsOn copyLib + + // Stop on first test failure + failFast = true + + // Properties as defined in Ant target javatest-basepath + // XXX Not sure of all that python.home is used for in tests. + systemProperty 'python.home', file(copyLib.destinationDir).parent + systemProperty 'python.test.source.dir', project.ext.testSourceDir + // Place cache outside the targets for jar task + systemProperty 'python.cachedir', "${project.buildDir}/cachedir" + // Logging level: default is message=INFO + //systemProperty 'python.verbose', 'CONFIG' + + include '**/*Test*' + + // Exclude based on Ant target javatest-basepath + exclude '**/InterpTestCase' + exclude '**/jythonTest*' // Must run interactively + exclude 'org/python/antlr/**' + exclude 'org/python/tests/imp/**' // See build.xml:importest + + // Some additional exclusions or else the task fails + + // FIXME: leaves stdin/out/err as PyFileWriter that has no fileno() + // causing _ioTest to fail. + exclude '**/jsr223/*' + + // FIXME: Tests that hard-code directory paths (use a symbol): + exclude 'org/python/compiler/custom_proxymaker/**' + exclude 'org/python/compiler/JavaMakerSmokeTest.class' + + // FIXME: Failing test finds project root from test class location + exclude 'org/python/core/PySystemState_registry_Test.class' + + // FIXME: Fails as sys._jy_console not set when run under Gradle + exclude 'org/python/util/InterpreterTest.class' + + doFirst { + println "systemProperties = $systemProperties" + } + +} + + +// ---------------- Miscellaneous fettling of the prepare phase ---------------- + +// Source is globally UTF-8 (well, nearly). +tasks.withType(JavaCompile) { + options.encoding = "UTF-8" +} + + + +// ---------------- Support for debugging -------------------------------------- + + +afterEvaluate { project -> + //dumpCP() + //dumpSS() +} + +void dumpCP() { + println('\nconfigurations.testCompile:') + configurations.testCompile.each { println it } + println('\nconfigurations.testRuntime:') + configurations.testRuntime.each { println it } + println('\nconfigurations.expose:') + configurations.expose.each { println it } + println('\nconfigurations.pycompile:') + configurations.pycompile.each { println it } +} + +void dumpSS() { + println '*** source sets ***' + for (ss in sourceSets) { + String name = ss.name + println ss + println " ${name}.compileConfigurationName = ${ss.compileConfigurationName}" + println " ${name}.implementationConfigurationName = ${ss.implementationConfigurationName}" + println " ${name}.runtimeConfigurationName = ${ss.runtimeConfigurationName}" + println " ${name}.java.srcDirs = ${ss.java.srcDirs}" + println " ${name}.antlr.srcDirs = ${ss.antlr.srcDirs}" + println " ${name}.resources.srcDirs = ${ss.resources.srcDirs}" + println " ${name}.output.dirs = ${ss.output.dirs.files}" + println " ${name}.output.classesDirs = ${ss.output.classesDirs.files}" + println " ${name}.output.resourcesDir = ${ss.output.resourcesDir}" + println " ${name}.classesTaskName = ${ss.classesTaskName}" + println " ${name}.compileJavaTaskName = ${ss.compileJavaTaskName}" + println " ${name}.jarTaskName = ${ss.jarTaskName}" + } +} diff --git a/build.xml b/build.xml index 7f0b68a76..3d2e9ee40 100644 --- a/build.xml +++ b/build.xml @@ -1,29 +1,50 @@ - + - - -Use case 1: developer build (in your local Jython copy) -------------------------------------------------------- - - call target 'developer-build' (the default for this build.xml) - -This build will create directories /build and /dist below basedir. - -Use case 2: full build for a release (using hg checkout) ---------------------------------------------------------- - - make sure you have access to the Jython mercurial repository - (http://hg.python.org/jython) - - override ant.properties (if necessary) - - call target 'full-build' - -This build will create a working directory named -full_build at the same level as your local directories -jython and installer. It will contain a big -jython_installer-${jython.version}.jar file suitable for installation. - -To build older releases, it may be necessary to use an older -build.xml, too (with the corresponding tag). For example it is not -possible to build Release_2_2alpha1 with this version of build.xml. + + +Case 1: developer build +----------------------- +Use the command: + ant developer-build +or just: + ant +as it is the default target. This build will create directories +/build and /dist below ${basedir}. +Jython will identify its version with a trailing "-DEV". + +Case 2: build an installer for the development version +------------------------------------------------------ +Use the command: + ant installer +An installer built this way does not include javadoc or source +JARs unless you build them first. It will be versioned as a +snapshot, e.g. ${jython.release}-SNAPSHOT. You can choose another name +for the snapshot, via a property: + ant -Dsnapshot.name=MYTEST installer + +Case 3: full build for a release (use clean, tagged checkout) +------------------------------------------------------------- +You do not have to have access to the Jython mercurial +repository, but you do need to be at the root of a checked-out +(i.e. newly cloned) source tree. The release aretefacts will be +marked as a snapshot (not an official release) if any of the +following apply: +- there is no .hg directory (this is not a repo), +- the source tree contains any extraneous files, +- files have been edited and not committed, +- the current state is not tagged with correct release, +- you supply the snapshot.name property. + +This will create a big jython-installer-${jython.release}.jar, +in the artefacts directory. + +See also https://jython-devguide.rtfd.io/en/latest/release_jy.html Note on targets --------------- @@ -32,349 +53,562 @@ Following an ant convention, the callable targets have a description attribute. Use ant -p to display these targets. All other targets may behave unpredictably if called directly. - Where ant looks for ant.properties ---------------------------------- 1. in user.home 2. in the same directory as this build.xml file The first setting of a property wins. Further settings are ignored. - -Actions for a release ---------------------- -See http://wiki.python.org/jython/JythonDeveloperGuide/HowToReleaseJython - - An example ant.properties file: ------------------------------- # - zxJDBC -oracle.jar=C:/workspace/HEAD/for_development/bisdevsrv28/jboss/server/infra/lib/ojdbc14.jar -#informix.jar=${basedir}/../externals/external-jars/ifxjdbc.jar +oracle.jar = ../support/ojdbc6.jar +informix.jar = ../support/jdbc-4.10.12.jar # - option for javac (build.compiler=modern is a global option to use standard jdk 1.7/1.8) #build.compiler=modern #jdk.target.version=1.7 #debug=false #deprecation=off - - + - + - + - - - - - + + - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - + + + + + + - - - + + - - + + - - + + + + + + - - - - - - - - - - - + + + - - - + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + - - - - - - - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - + + + + - + + + . Build environment for ${ant.project.name} (Note: if ${propertyname} is displayed, then the property is not set) + --- build Jython version --- + jython.version.short = '${jython.version.short}' + jython.release = '${jython.release}' + jython.version = '${jython.version}' + snapshot.name = '${snapshot.name}' + snapshot.suffix = '${snapshot.suffix}' + jython.dev.jar = '${jython.dev.jar}' + jython.deploy.jar = '${jython.deploy.jar}' + jython.standalone.jar = '${jython.standalone.jar}' + jython.javadoc.jar = '${jython.javadoc.jar}' + jython.sources.jar = '${jython.sources.jar}' + jar.update = '${jar.update}' --- optional libraries --- - oracle location = '${oracle.jar}' - informix location = '${informix.jar}' - oracle = '${oracle.present}' - informix = '${informix.present}' + informix = '${informix.jar}' + informix.present = '${informix.present}' + oracle = '${oracle.jar}' + oracle.present = '${oracle.present}' --- properties --- - work.dir = '${work.dir}' - jython.base.dir = '${jython.base.dir}' - source.dir = '${source.dir}' - output.dir = '${output.dir}' - compile.dir = '${compile.dir}' - exposed.dir = '${exposed.dir}' - dist.dir = '${dist.dir}' - apidoc.dir = '${apidoc.dir}' - templates.dir = '${templates.dir}' - templates.lazy = '${templates.lazy}' - python.lib = '${python.lib}' - build.compiler = '${build.compiler}' - jdk.target.version = '${jdk.target.version}' - jdk.source.version = '${jdk.source.version}' - deprecation = '${deprecation}' - debug = '${debug}' - nowarn = '${nowarn}' - test = '${test}' - test.source.dir = '${test.source.dir}' - --- properties (used for full-build only) --- - checkout.dir = '${checkout.dir}' - javahl.dir = '${javahl.dir}' - do.snapshot.build = '${do.snapshot.build}' - snapshot.revision = '${snapshot.revision}' - do.checkout = '${do.checkout}' - - - - - - - - - - - - - - - - - - - + basedir = '${basedir}' + source.dir = '${source.dir}' + build.dir = '${build.dir}' + compile.dir = '${compile.dir}' + exposed.dir = '${exposed.dir}' + gensrc.dir = '${gensrc.dir}' + dist.dir = '${dist.dir}' + apidoc.dir = '${apidoc.dir}' + templates.dir = '${templates.dir}' + templates.lazy = '${templates.lazy}' + python.lib = '${python.lib}' + --- compiler options --- + build.compiler = '${build.compiler}' + jdk.target.version = '${jdk.target.version}' + jdk.source.version = '${jdk.source.version}' + deprecation = '${deprecation}' + debug = '${debug}' + nowarn = '${nowarn}' + main.classpath = '${ant.refid:main.classpath}' + --- test config --- + test = '${test}' + test.source.dir = '${test.source.dir}' + reports.dir = '${reports.dir}' + - + + --- properties only used for a full-build --- + hg.present = '${hg.present}' + build.hg.is_unmodified = '${build.hg.is_unmodified}' + build.hg.is_clean = '${build.hg.is_clean}' + build.hg.is_tagged = '${build.hg.is_tagged}' + build.hg.branch = '${build.hg.branch}' + build.hg.tag = '${build.hg.tag}' + build.hg.version = '${build.hg.version}' + + + - - - - - - - - - + + + + + + + + - - + - + + + + - - - - + + - - - - - - - + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + +${message} + +${build.hg.status} + - - - - - - - - + + + + + + + + + + - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + + - - - - + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + + + + + + - - - - - + + + + + + + + + + + + Writing hg and build metadata to version.properties. + jython.version = ${jython.version} + build.hg.branch = ${build.hg.branch} + build.hg.version = ${build.hg.version} + build.hg.tag = ${build.hg.tag} + @@ -394,54 +628,95 @@ jython.build.hg_tag=${build.hg.tag} jython.build.hg_version=${build.hg.version} - - - - - ======================= - -------------------------- + + + -This is a snapshot build. -It reflects the current development status. - -The readme text for the next release will be like: + + + + + + + + + + + - + + + +------------------------------------------------------------------------- +This is a snapshot build. It reflects the current development status. +The text for an official release would continue like ... +------------------------------------------------------------------------- + + + + + + + + + + + + + + + + - + + nowarn="${nowarn}" + includeantruntime="false"> - + - - + + + + + + + + + + + + + + + - + - - - + + + @@ -455,32 +730,36 @@ The readme text for the next release will be like: --> - + + + - - + + - + nowarn="${nowarn}" + includeantruntime="false"> @@ -492,20 +771,11 @@ The readme text for the next release will be like: debug="${debug}" deprecation="${deprecation}" nowarn="${nowarn}" + includeantruntime="false" encoding="UTF-8"> - - - - @@ -516,7 +786,7 @@ The readme text for the next release will be like: - + @@ -539,7 +809,6 @@ The readme text for the next release will be like: - @@ -547,49 +816,56 @@ The readme text for the next release will be like: + + includesfile="${basedir}/CoreExposed.includes"/> - - + + + + + + + - - + + - - - - + + + - + - + - - - + + + + - + - + - + - + - + - + - + + @@ -597,6 +873,7 @@ The readme text for the next release will be like: + @@ -608,22 +885,25 @@ The readme text for the next release will be like: - - - - - - - + + + + + + + - + + + +
@@ -637,18 +917,20 @@ The readme text for the next release will be like: - - - + + + + +
- + @@ -656,20 +938,25 @@ The readme text for the next release will be like:
+
- + - + - + @@ -681,10 +968,13 @@ The readme text for the next release will be like: + + +
- + @@ -701,9 +991,11 @@ The readme text for the next release will be like: + - - + + + + - - + + + + + @@ -730,46 +1029,48 @@ The readme text for the next release will be like: - - copy CPython LICENSE from ${checkout.dir}/python - - - - - copy misc files from ${jython.base.dir} + + copy misc files from ${basedir} - + + + + + + + + + - copy sources from ${jython.base.dir} + copy sources from ${basedir} - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - copy the demo files from ${jython.base.dir}/Demo + copy the demo files from ${basedir}/Demo - + @@ -782,16 +1083,21 @@ The readme text for the next release will be like: - + + + + - + excludes="test/**,lib2to3/tests/**,lib2to3/tests/data/myfixes/**"/> - + - - + + + + @@ -821,39 +1129,41 @@ The readme text for the next release will be like: - + - + + - + - + - + + - + - + - - - - + + - - - compiling installer from ${installer.src.dir} + includeantruntime="false" /> + copy installer classes to ${dist.dir} @@ -871,7 +1182,9 @@ The readme text for the next release will be like: - + + copy installer icon to ${dist.dir} @@ -881,9 +1194,11 @@ The readme text for the next release will be like: + building installer .jar file - + + @@ -900,6 +1215,9 @@ The readme text for the next release will be like: + + +
@@ -907,7 +1225,7 @@ The readme text for the next release will be like:
- + @@ -918,10 +1236,10 @@ The readme text for the next release will be like: - - @@ -934,12 +1252,21 @@ The readme text for the next release will be like: - - - + + + + + + + + + + + - @@ -952,7 +1279,6 @@ The readme text for the next release will be like: - @@ -973,7 +1299,7 @@ The readme text for the next release will be like: - + @@ -1041,10 +1367,11 @@ The readme text for the next release will be like: - + @@ -1058,6 +1385,7 @@ The readme text for the next release will be like: + @@ -1070,10 +1398,11 @@ The readme text for the next release will be like: + @@ -1084,11 +1413,12 @@ The readme text for the next release will be like: - + + @@ -1098,47 +1428,61 @@ The readme text for the next release will be like: - + + - - + + + + + + + + + + - - + + + + + + - - - + + + - + @@ -1170,6 +1514,11 @@ The readme text for the next release will be like: or set jdk.home explicitly --> + + + + + creating ${bugtests.dir}/support_config.py @@ -1177,7 +1526,7 @@ The readme text for the next release will be like: # safe to edit by hand (won't be overwritten) java_home="${jdk.home}" jython_home="${dist.dir}" -classpath="${dist.dir}/${jython.dev.jar}${path.separator}classes" +classpath="${ant.refid:bugtest.classpath}" diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 68c0747c6..000000000 --- a/circle.yml +++ /dev/null @@ -1,17 +0,0 @@ -machine: - java: - version: openjdk7 - -# refactor into a script some time -test: - override: - - case $CIRCLE_NODE_INDEX in 0) sudo update-alternatives --set java /usr/lib/jvm/java-7-openjdk-amd64/jre/bin/java; java -version ;; 1) sudo update-alternatives --set java /usr/lib/jvm/jdk1.7.0/bin/java; java -version ;; esac: - parallel: true - timeout: 2400 - - if [ $CIRCLE_NODE_INDEX -lt 2 ]; then ant developer-build regrtest-travis; elif [ $CIRCLE_NODE_INDEX -eq 2 ]; then ant developer-build; sudo update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java; ant regrtest-travis; fi: - parallel: true - timeout: 2400 - - post: - - mkdir -p $CIRCLE_TEST_REPORTS/junit/; cp -a dist/testreports/* $CIRCLE_TEST_REPORTS/junit/: - parallel: true diff --git a/extlibs/antlr-3.1.3.jar b/extlibs/antlr-3.1.3.jar deleted file mode 100644 index 0ec52f864..000000000 Binary files a/extlibs/antlr-3.1.3.jar and /dev/null differ diff --git a/extlibs/antlr-complete-3.5.2.jar b/extlibs/antlr-complete-3.5.2.jar new file mode 100644 index 000000000..260de7634 Binary files /dev/null and b/extlibs/antlr-complete-3.5.2.jar differ diff --git a/extlibs/antlr-runtime-3.1.3.jar b/extlibs/antlr-runtime-3.1.3.jar deleted file mode 100644 index b0a9ea69f..000000000 Binary files a/extlibs/antlr-runtime-3.1.3.jar and /dev/null differ diff --git a/extlibs/antlr-runtime-3.5.2.jar b/extlibs/antlr-runtime-3.5.2.jar new file mode 100644 index 000000000..d48e3e867 Binary files /dev/null and b/extlibs/antlr-runtime-3.5.2.jar differ diff --git a/extlibs/asm-5.0.3.jar b/extlibs/asm-5.0.3.jar deleted file mode 100644 index 573535b1d..000000000 Binary files a/extlibs/asm-5.0.3.jar and /dev/null differ diff --git a/extlibs/asm-7.1.jar b/extlibs/asm-7.1.jar new file mode 100644 index 000000000..355eb08db Binary files /dev/null and b/extlibs/asm-7.1.jar differ diff --git a/extlibs/asm-commons-5.0.3.jar b/extlibs/asm-commons-5.0.3.jar deleted file mode 100644 index 514a6dc2e..000000000 Binary files a/extlibs/asm-commons-5.0.3.jar and /dev/null differ diff --git a/extlibs/asm-commons-7.1.jar b/extlibs/asm-commons-7.1.jar new file mode 100644 index 000000000..31ffb987d Binary files /dev/null and b/extlibs/asm-commons-7.1.jar differ diff --git a/extlibs/asm-util-5.0.3.jar b/extlibs/asm-util-5.0.3.jar deleted file mode 100644 index e89f1b7b6..000000000 Binary files a/extlibs/asm-util-5.0.3.jar and /dev/null differ diff --git a/extlibs/asm-util-7.1.jar b/extlibs/asm-util-7.1.jar new file mode 100644 index 000000000..5e61f2c10 Binary files /dev/null and b/extlibs/asm-util-7.1.jar differ diff --git a/extlibs/bcpkix-jdk15on-1.54.jar b/extlibs/bcpkix-jdk15on-1.54.jar deleted file mode 100644 index 86f7f0be1..000000000 Binary files a/extlibs/bcpkix-jdk15on-1.54.jar and /dev/null differ diff --git a/extlibs/bcpkix-jdk15on-1.62.jar b/extlibs/bcpkix-jdk15on-1.62.jar new file mode 100644 index 000000000..d63da57bd Binary files /dev/null and b/extlibs/bcpkix-jdk15on-1.62.jar differ diff --git a/extlibs/bcprov-jdk15on-1.54.jar b/extlibs/bcprov-jdk15on-1.54.jar deleted file mode 100644 index bd95185ae..000000000 Binary files a/extlibs/bcprov-jdk15on-1.54.jar and /dev/null differ diff --git a/extlibs/bcprov-jdk15on-1.62.jar b/extlibs/bcprov-jdk15on-1.62.jar new file mode 100644 index 000000000..c52b16e4e Binary files /dev/null and b/extlibs/bcprov-jdk15on-1.62.jar differ diff --git a/extlibs/commons-compress-1.10.jar b/extlibs/commons-compress-1.10.jar deleted file mode 100644 index 75ced20e1..000000000 Binary files a/extlibs/commons-compress-1.10.jar and /dev/null differ diff --git a/extlibs/commons-compress-1.19.jar b/extlibs/commons-compress-1.19.jar new file mode 100644 index 000000000..5c9f52a29 Binary files /dev/null and b/extlibs/commons-compress-1.19.jar differ diff --git a/extlibs/failureaccess-1.0.1.jar b/extlibs/failureaccess-1.0.1.jar new file mode 100644 index 000000000..9b56dc751 Binary files /dev/null and b/extlibs/failureaccess-1.0.1.jar differ diff --git a/extlibs/guava-19.0.jar b/extlibs/guava-19.0.jar deleted file mode 100644 index b175ca867..000000000 Binary files a/extlibs/guava-19.0.jar and /dev/null differ diff --git a/extlibs/guava-28.0-android.jar b/extlibs/guava-28.0-android.jar new file mode 100644 index 000000000..516fc5fa1 Binary files /dev/null and b/extlibs/guava-28.0-android.jar differ diff --git a/extlibs/icu4j-56.1.jar b/extlibs/icu4j-59_1.jar similarity index 55% rename from extlibs/icu4j-56.1.jar rename to extlibs/icu4j-59_1.jar index 226307953..3dc69c8a1 100644 Binary files a/extlibs/icu4j-56.1.jar and b/extlibs/icu4j-59_1.jar differ diff --git a/extlibs/jarjar-1.4.jar b/extlibs/jarjar-1.4.jar deleted file mode 100644 index 68b9db9aa..000000000 Binary files a/extlibs/jarjar-1.4.jar and /dev/null differ diff --git a/extlibs/jarjar-1.7.2.jar b/extlibs/jarjar-1.7.2.jar new file mode 100644 index 000000000..305260ea8 Binary files /dev/null and b/extlibs/jarjar-1.7.2.jar differ diff --git a/extlibs/jffi-1.2.10.jar b/extlibs/jffi-1.2.10.jar deleted file mode 100644 index e09f1110a..000000000 Binary files a/extlibs/jffi-1.2.10.jar and /dev/null differ diff --git a/extlibs/jffi-1.2.20.jar b/extlibs/jffi-1.2.20.jar new file mode 100644 index 000000000..011e3afa8 Binary files /dev/null and b/extlibs/jffi-1.2.20.jar differ diff --git a/extlibs/jffi-aarch64-Linux.jar b/extlibs/jffi-aarch64-Linux.jar new file mode 100644 index 000000000..1d4438e3f Binary files /dev/null and b/extlibs/jffi-aarch64-Linux.jar differ diff --git a/extlibs/jffi-arm-Linux.jar b/extlibs/jffi-arm-Linux.jar index b3c5d977c..f9a048b77 100644 Binary files a/extlibs/jffi-arm-Linux.jar and b/extlibs/jffi-arm-Linux.jar differ diff --git a/extlibs/jffi-ppc-AIX.jar b/extlibs/jffi-ppc-AIX.jar index 8235a3484..eed0ab732 100644 Binary files a/extlibs/jffi-ppc-AIX.jar and b/extlibs/jffi-ppc-AIX.jar differ diff --git a/extlibs/jffi-ppc64-Linux.jar b/extlibs/jffi-ppc64-Linux.jar index 8235a3484..cfae4bbf6 100644 Binary files a/extlibs/jffi-ppc64-Linux.jar and b/extlibs/jffi-ppc64-Linux.jar differ diff --git a/extlibs/jffi-ppc64le-Linux.jar b/extlibs/jffi-ppc64le-Linux.jar new file mode 100644 index 000000000..7931dd1c2 Binary files /dev/null and b/extlibs/jffi-ppc64le-Linux.jar differ diff --git a/extlibs/jffi-x86_64-OpenBSD.jar b/extlibs/jffi-x86_64-OpenBSD.jar index 8235a3484..3e14e03e4 100644 Binary files a/extlibs/jffi-x86_64-OpenBSD.jar and b/extlibs/jffi-x86_64-OpenBSD.jar differ diff --git a/extlibs/jline-2.13.jar b/extlibs/jline-2.13.jar deleted file mode 100644 index 66d7b1fec..000000000 Binary files a/extlibs/jline-2.13.jar and /dev/null differ diff --git a/extlibs/jline-2.14.5.jar b/extlibs/jline-2.14.5.jar new file mode 100644 index 000000000..761acd41a Binary files /dev/null and b/extlibs/jline-2.14.5.jar differ diff --git a/extlibs/jnr-constants-0.9.0.jar b/extlibs/jnr-constants-0.9.0.jar deleted file mode 100644 index 52040d3c8..000000000 Binary files a/extlibs/jnr-constants-0.9.0.jar and /dev/null differ diff --git a/extlibs/jnr-constants-0.9.12.jar b/extlibs/jnr-constants-0.9.12.jar new file mode 100644 index 000000000..d894741f4 Binary files /dev/null and b/extlibs/jnr-constants-0.9.12.jar differ diff --git a/extlibs/jnr-ffi-2.0.7.jar b/extlibs/jnr-ffi-2.0.7.jar deleted file mode 100644 index 4393c6e49..000000000 Binary files a/extlibs/jnr-ffi-2.0.7.jar and /dev/null differ diff --git a/extlibs/jnr-ffi-2.1.10.jar b/extlibs/jnr-ffi-2.1.10.jar new file mode 100644 index 000000000..d3382b5c4 Binary files /dev/null and b/extlibs/jnr-ffi-2.1.10.jar differ diff --git a/extlibs/jnr-netdb-1.1.5.jar b/extlibs/jnr-netdb-1.1.6.jar similarity index 87% rename from extlibs/jnr-netdb-1.1.5.jar rename to extlibs/jnr-netdb-1.1.6.jar index 365ed049c..0f49b70d6 100644 Binary files a/extlibs/jnr-netdb-1.1.5.jar and b/extlibs/jnr-netdb-1.1.6.jar differ diff --git a/extlibs/jnr-posix-3.0.23.jar b/extlibs/jnr-posix-3.0.23.jar deleted file mode 100644 index 2c8845382..000000000 Binary files a/extlibs/jnr-posix-3.0.23.jar and /dev/null differ diff --git a/extlibs/jnr-posix-3.0.50.jar b/extlibs/jnr-posix-3.0.50.jar new file mode 100644 index 000000000..1288fce57 Binary files /dev/null and b/extlibs/jnr-posix-3.0.50.jar differ diff --git a/extlibs/mockrunner-0.4.1/jar/xml-apis-2.11.0.jar b/extlibs/mockrunner-0.4.1/jar/xml-apis-2.11.0.jar new file mode 100644 index 000000000..46733464f Binary files /dev/null and b/extlibs/mockrunner-0.4.1/jar/xml-apis-2.11.0.jar differ diff --git a/extlibs/mockrunner-0.4.1/readme.txt b/extlibs/mockrunner-0.4.1/readme.txt index 685001699..7afac7152 100644 --- a/extlibs/mockrunner-0.4.1/readme.txt +++ b/extlibs/mockrunner-0.4.1/readme.txt @@ -1,2 +1,9 @@ -This contains the minimal set of jars from mockrunner-0.4.1 to run the modjy tests against j2ee1.3 -with jdk1.5. +This contains the minimal set of jars from mockrunner-0.4.1 to run the modjy +tests against j2ee1.3 with jdk1.5. + +These are run from the main Jython directory as part of "ant test", +or from tests/modjy with "ant". In the latter case, JYTHON_HOME must +be set to the project/dist folder and MOCKRUNNER_HOME to this folder. + +xml-apis-*.jar is added to mockrunner because it is needed for these tests, +but not for Jython generally. diff --git a/extlibs/mysql-connector-java-5.1.42-bin.jar b/extlibs/mysql-connector-java-5.1.42-bin.jar new file mode 100644 index 000000000..4c6df38c1 Binary files /dev/null and b/extlibs/mysql-connector-java-5.1.42-bin.jar differ diff --git a/extlibs/mysql-connector-java-5.1.6.jar b/extlibs/mysql-connector-java-5.1.6.jar deleted file mode 100644 index 0539039f7..000000000 Binary files a/extlibs/mysql-connector-java-5.1.6.jar and /dev/null differ diff --git a/extlibs/netty-buffer-4.1.4.Final.jar b/extlibs/netty-buffer-4.1.4.Final.jar deleted file mode 100644 index 5fd2d10df..000000000 Binary files a/extlibs/netty-buffer-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-buffer-4.1.45.Final.jar b/extlibs/netty-buffer-4.1.45.Final.jar new file mode 100644 index 000000000..45d9ff28a Binary files /dev/null and b/extlibs/netty-buffer-4.1.45.Final.jar differ diff --git a/extlibs/netty-codec-4.1.4.Final.jar b/extlibs/netty-codec-4.1.4.Final.jar deleted file mode 100644 index 6526db4b3..000000000 Binary files a/extlibs/netty-codec-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-codec-4.1.45.Final.jar b/extlibs/netty-codec-4.1.45.Final.jar new file mode 100644 index 000000000..e8378e766 Binary files /dev/null and b/extlibs/netty-codec-4.1.45.Final.jar differ diff --git a/extlibs/netty-common-4.1.4.Final.jar b/extlibs/netty-common-4.1.4.Final.jar deleted file mode 100644 index 44d1d5943..000000000 Binary files a/extlibs/netty-common-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-common-4.1.45.Final.jar b/extlibs/netty-common-4.1.45.Final.jar new file mode 100644 index 000000000..038f1f72c Binary files /dev/null and b/extlibs/netty-common-4.1.45.Final.jar differ diff --git a/extlibs/netty-handler-4.1.4.Final.jar b/extlibs/netty-handler-4.1.4.Final.jar deleted file mode 100644 index 405779c00..000000000 Binary files a/extlibs/netty-handler-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-handler-4.1.45.Final.jar b/extlibs/netty-handler-4.1.45.Final.jar new file mode 100644 index 000000000..ef3d012e7 Binary files /dev/null and b/extlibs/netty-handler-4.1.45.Final.jar differ diff --git a/extlibs/netty-resolver-4.1.4.Final.jar b/extlibs/netty-resolver-4.1.4.Final.jar deleted file mode 100644 index 803304844..000000000 Binary files a/extlibs/netty-resolver-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-resolver-4.1.45.Final.jar b/extlibs/netty-resolver-4.1.45.Final.jar new file mode 100644 index 000000000..defcf0483 Binary files /dev/null and b/extlibs/netty-resolver-4.1.45.Final.jar differ diff --git a/extlibs/netty-transport-4.1.4.Final.jar b/extlibs/netty-transport-4.1.4.Final.jar deleted file mode 100644 index 865dd4167..000000000 Binary files a/extlibs/netty-transport-4.1.4.Final.jar and /dev/null differ diff --git a/extlibs/netty-transport-4.1.45.Final.jar b/extlibs/netty-transport-4.1.45.Final.jar new file mode 100644 index 000000000..2a16b1ced Binary files /dev/null and b/extlibs/netty-transport-4.1.45.Final.jar differ diff --git a/extlibs/postgresql-42.1.1.jre7.jar b/extlibs/postgresql-42.1.1.jre7.jar new file mode 100644 index 000000000..99b60a338 Binary files /dev/null and b/extlibs/postgresql-42.1.1.jre7.jar differ diff --git a/extlibs/postgresql-8.3-603.jdbc4.jar b/extlibs/postgresql-8.3-603.jdbc4.jar deleted file mode 100644 index 0bf0de057..000000000 Binary files a/extlibs/postgresql-8.3-603.jdbc4.jar and /dev/null differ diff --git a/extlibs/xercesImpl-2.11.0.jar b/extlibs/xercesImpl-2.12.0.jar similarity index 68% rename from extlibs/xercesImpl-2.11.0.jar rename to extlibs/xercesImpl-2.12.0.jar index 0aaa990f3..b69d01dac 100644 Binary files a/extlibs/xercesImpl-2.11.0.jar and b/extlibs/xercesImpl-2.12.0.jar differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000..1948b9074 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000..290541c73 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 000000000..cccdd3d51 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 000000000..e95643d6a --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/grammar/Python.g b/grammar/Python.g index a6cb0d9eb..3ee564681 100644 --- a/grammar/Python.g +++ b/grammar/Python.g @@ -239,12 +239,15 @@ private ErrorHandler errorHandler; } /** - * Taken directly from antlr's Lexer.java -- needs to be re-integrated every time - * we upgrade from Antlr (need to consider a Lexer subclass, though the issue would - * remain). + * The text of this is mostly taken directly from ANTLR's Lexer.java, + * and ought to track changes there each time we get a new version, + * ... if there are any after 3.5.2. Also in PythonPartial.g. */ + @Override public Token nextToken() { + // -- begin Jython addition startPos = getCharPositionInLine(); + // -- end Jython addition while (true) { state.token = null; state.channel = Token.DEFAULT_CHANNEL; @@ -253,10 +256,12 @@ private ErrorHandler errorHandler; state.tokenStartLine = input.getLine(); state.text = null; if ( input.LA(1)==CharStream.EOF ) { + // -- begin Jython addition if (implicitLineJoiningLevel > 0) { eofWhileNested = true; } - return Token.EOF_TOKEN; + // -- end Jython addition + return getEOFToken(); } try { mTokens(); @@ -267,21 +272,30 @@ private ErrorHandler errorHandler; continue; } return state.token; + // -- begin Jython addition } catch (NoViableAltException nva) { reportError(nva); errorHandler.recover(this, nva); // throw out current char and try again } catch (FailedPredicateException fp) { - //XXX: added this for failed STRINGPART -- the FailedPredicateException - // hides a NoViableAltException. This should be the only - // FailedPredicateException that gets thrown by the lexer. + // Added this for failed STRINGPART -- the FailedPredicateException + // hides a NoViableAltException. This should be the only + // FailedPredicateException that gets thrown by the lexer. reportError(fp); errorHandler.recover(this, fp); // throw out current char and try again - } catch (RecognitionException re) { + // -- end Jython addition + } catch (MismatchedRangeException re) { + reportError(re); + // matchRange() routine has already called recover() + } catch (MismatchedTokenException re) { reportError(re); // match() routine has already called recover() + } catch (RecognitionException re) { + reportError(re); + recover(re); // throw out current char and try again } } } + @Override public void displayRecognitionError(String[] tokenNames, RecognitionException e) { //Do nothing. We will handle error display elsewhere. @@ -995,10 +1009,9 @@ import_from //import_as_names: import_as_name (',' import_as_name)* [','] import_as_names returns [List atypes] - : n+=import_as_name (COMMA! n+=import_as_name)* - { - $atypes = $n; - } + @init{$atypes = new ArrayList();} + : n=import_as_name {$atypes.add($n.atype);} + (COMMA! n=import_as_name {$atypes.add($n.atype);})* ; //import_as_name: NAME [('as' | NAME) NAME] @@ -1029,32 +1042,31 @@ dotted_as_name //dotted_as_names: dotted_as_name (',' dotted_as_name)* dotted_as_names returns [List atypes] - : d+=dotted_as_name (COMMA! d+=dotted_as_name)* - { - $atypes = $d; - } + @init{$atypes = new ArrayList();} + : d=dotted_as_name {$atypes.add($d.atype);} + (COMMA! d=dotted_as_name {$atypes.add($d.atype);})* ; //dotted_name: NAME ('.' NAME)* dotted_name returns [List names] - : NAME (DOT dn+=attr)* - { - $names = actions.makeDottedName($NAME, $dn); - } + @init{List dnList = new ArrayList<>();} + : NAME (DOT dn=attr {dnList.add($dn.tree);})* + {$names = actions.makeDottedName($NAME, dnList);} ; //global_stmt: 'global' NAME (',' NAME)* global_stmt @init { stmt stype = null; + List names = new ArrayList<>(); } @after { $global_stmt.tree = stype; } - : GLOBAL n+=NAME (COMMA n+=NAME)* + : GLOBAL n=NAME {names.add($n);} (COMMA n=NAME {names.add($n);})* { - stype = new Global($GLOBAL, actions.makeNames($n), actions.makeNameNodes($n)); + stype = new Global($GLOBAL, actions.makeNames(names), actions.makeNameNodes(names)); } ; @@ -1185,14 +1197,17 @@ for_stmt try_stmt @init { stmt stype = null; + List exceptClauses = new ArrayList<>(); } @after { $try_stmt.tree = stype; } : TRY COLON trysuite=suite[!$suite.isEmpty() && $suite::continueIllegal] - ( e+=except_clause+ (ORELSE COLON elsesuite=suite[!$suite.isEmpty() && $suite::continueIllegal])? (FINALLY COLON finalsuite=suite[true])? + ( (e=except_clause {exceptClauses.add((excepthandler)$e.tree);})+ + (ORELSE COLON elsesuite=suite[!$suite.isEmpty() && $suite::continueIllegal])? + (FINALLY COLON finalsuite=suite[true])? { - stype = actions.makeTryExcept($TRY, $trysuite.stypes, $e, $elsesuite.stypes, $finalsuite.stypes); + stype = actions.makeTryExcept($TRY, $trysuite.stypes, exceptClauses, $elsesuite.stypes, $finalsuite.stypes); } | FINALLY COLON finalsuite=suite[true] { @@ -1205,14 +1220,15 @@ try_stmt with_stmt @init { stmt stype = null; + List withList = new ArrayList<>(); } @after { $with_stmt.tree = stype; } - : WITH w+=with_item (options {greedy=true;}:COMMA w+=with_item)* COLON suite[false] - { - stype = actions.makeWith($WITH, $w, $suite.stypes); - } + : WITH w=with_item {withList.add((With)$w.tree);} + (options {greedy=true;}:COMMA w=with_item {withList.add((With)$w.tree);})* + COLON suite[false] + {stype = actions.makeWith($WITH, withList, $suite.stypes);} ; //with_item: test ['as' expr] @@ -1252,7 +1268,7 @@ except_clause //suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT suite - [boolean fromFinally] returns [List stypes] + [boolean fromFinally] returns [List stypes] scope { boolean continueIllegal; } @@ -1754,9 +1770,9 @@ atom } ) RCURLY - | lb=BACKQUOTE testlist[expr_contextType.Load] rb=BACKQUOTE + | lb=BACKQUOTE testlist1[expr_contextType.Load] rb=BACKQUOTE { - etype = new Repr($lb, actions.castExpr($testlist.tree)); + etype = new Repr($lb, actions.castExpr($testlist1.tree)); } | name_or_print { @@ -1966,10 +1982,11 @@ exprlist //Needed as an exprlist that does not produce tuples for del_stmt. del_list returns [List etypes] - : e+=expr[expr_contextType.Del] (options {k=2;}: COMMA e+=expr[expr_contextType.Del])* (COMMA)? - { - $etypes = actions.makeDeleteList($e); - } + @init{List exprList = new ArrayList<>();} + : e=expr[expr_contextType.Del] {exprList.add($e.tree);} + (options {k=2;}: COMMA e=expr[expr_contextType.Del] + {exprList.add($e.tree);})* (COMMA)? + {$etypes = actions.makeDeleteList(exprList);} ; //testlist: test (',' test)* [','] @@ -2189,6 +2206,26 @@ comp_if[List gens, List ifs] } ; +// Variant of testlist used between BACKQUOTEs (the deprecated back-tick repr()) only +//testlist1: test (',' test)* +testlist1[expr_contextType ctype] +@init { + expr etype = null; +} +@after { + if (etype != null) { + $testlist1.tree = etype; + } +} + : t+=test[ctype] + ( + COMMA t+=test[ctype] + { + etype = new Tuple($testlist1.start, actions.castExprs($t), ctype); + } + )* + ; + //yield_expr: 'yield' [testlist] yield_expr returns [expr etype] @@ -2383,16 +2420,14 @@ STRING } ; -/** the two '"'? cause a warning -- is there a way to avoid that? */ fragment TRIQUOTE - : '"'? '"'? (ESC|~('\\'|'"'))+ + : ('"' '"'?)? (ESC|~('\\'|'"'))+ ; -/** the two '\''? cause a warning -- is there a way to avoid that? */ fragment TRIAPOS - : '\''? '\''? (ESC|~('\\'|'\''))+ + : ('\'' '\''?)? (ESC|~('\\'|'\''))+ ; fragment diff --git a/grammar/PythonPartial.g b/grammar/PythonPartial.g index 022e82d11..6088cb9d1 100644 --- a/grammar/PythonPartial.g +++ b/grammar/PythonPartial.g @@ -116,12 +116,15 @@ private ErrorHandler errorHandler; } /** - * Taken directly from antlr's Lexer.java -- needs to be re-integrated every time - * we upgrade from Antlr (need to consider a Lexer subclass, though the issue would - * remain). + * The text of this is mostly taken directly from ANTLR's Lexer.java, + * and ought to track changes there each time we get a new version, + * ... if there are any after 3.5.2. Also in PythonPartial.g. */ + @Override public Token nextToken() { + // -- begin Jython addition startPos = getCharPositionInLine(); + // -- end Jython addition while (true) { state.token = null; state.channel = Token.DEFAULT_CHANNEL; @@ -130,10 +133,12 @@ private ErrorHandler errorHandler; state.tokenStartLine = input.getLine(); state.text = null; if ( input.LA(1)==CharStream.EOF ) { + // -- begin Jython addition if (implicitLineJoiningLevel > 0) { eofWhileNested = true; } - return Token.EOF_TOKEN; + // -- end Jython addition + return getEOFToken(); } try { mTokens(); @@ -144,18 +149,28 @@ private ErrorHandler errorHandler; continue; } return state.token; + // -- begin Jython addition } catch (NoViableAltException nva) { errorHandler.reportError(this, nva); errorHandler.recover(this, nva); // throw out current char and try again } catch (FailedPredicateException fp) { - //XXX: added this for failed STRINGPART -- the FailedPredicateException - // hides a NoViableAltException. This should be the only - // FailedPredicateException that gets thrown by the lexer. + // Added this for failed STRINGPART -- the FailedPredicateException + // hides a NoViableAltException. This should be the only + // FailedPredicateException that gets thrown by the lexer. errorHandler.reportError(this, fp); errorHandler.recover(this, fp); // throw out current char and try again + // -- end Jython addition + } catch (MismatchedRangeException re) { + reportError(re); + // matchRange() routine has already called recover() + } catch (MismatchedTokenException re) { + reportError(re); + // match() routine has already called recover() } catch (RecognitionException re) { + // -- Jython replaces: reportError(this, re) with: errorHandler.reportError(this, re); - // match() routine has already called recover() + // -- end Jython replacement + recover(re); // throw out current char and try again } } } @@ -172,7 +187,7 @@ single_input //eval_input: testlist NEWLINE* ENDMARKER eval_input - : LEADING_WS? (NEWLINE)* testlist? (NEWLINE)* EOF + : LEADING_WS? (NEWLINE)* (testlist (NEWLINE)*)? EOF ; //not in CPython's Grammar file @@ -729,7 +744,7 @@ atom | ) RCURLY - | BACKQUOTE testlist BACKQUOTE + | BACKQUOTE testlist1 BACKQUOTE | NAME | INT | LONGINT @@ -892,6 +907,12 @@ comp_if : IF test comp_iter? ; +// Variant of testlist used between BACKQUOTEs (the deprecated back-tick repr()) only +//testlist1: test (',' test)* +testlist1 + : test (COMMA test)* + ; + //yield_expr: 'yield' [testlist] yield_expr : YIELD testlist? @@ -1091,13 +1112,13 @@ STRINGPART /** the two '"'? cause a warning -- is there a way to avoid that? */ fragment TRIQUOTE - : '"'? '"'? (ESC|~('\\'|'"'))+ + : ('"' '"'?)? (ESC|~('\\'|'"'))+ ; /** the two '\''? cause a warning -- is there a way to avoid that? */ fragment TRIAPOS - : '\''? '\''? (ESC|~('\\'|'\''))+ + : ('\'' '\''?)? (ESC|~('\\'|'\''))+ ; fragment @@ -1118,7 +1139,7 @@ CONTINUED_LINE | nl=NEWLINE { extraNewlines = true; - } + } | ) { if (input.LA(1) == -1) { diff --git a/installer/src/java/org/python/util/install/ChildProcess.java b/installer/src/java/org/python/util/install/ChildProcess.java index b58b11f1f..4f784bc57 100644 --- a/installer/src/java/org/python/util/install/ChildProcess.java +++ b/installer/src/java/org/python/util/install/ChildProcess.java @@ -6,7 +6,9 @@ import java.io.InputStreamReader; import java.nio.file.Path; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * Easy start of a child process. @@ -85,6 +87,11 @@ public List getOutput() { */ private String _command[] = null; + /** + * Environment name-value pairs to add or remove (if null) at the start of {@link #run()}. + */ + private Map _environmentChanges = new HashMap<>(); + /** * The timeout (in milliseconds) */ @@ -170,6 +177,16 @@ public String[] getCommand() { public void setCWD(Path cwd) { _cwd = cwd; } + /** + * Set or delete an environment variable for the subsequently run command. + * + * @param key name of variable + * @param value new value or {@code null} to delete it. + */ + public void putEnvironment(String key, String value) { + _environmentChanges.put(key, value); + } + public Path getCWD() { return _cwd; } /** @@ -263,14 +280,23 @@ public int run() { try { // determine start time _startTime = System.currentTimeMillis(); - // start the process + // Create and configure the process specification ProcessBuilder pb = new ProcessBuilder(); pb.command(getCommand()); if (getCWD() != null) { pb.directory(getCWD().toFile()); } + // Adjust the environment variables from the default System.getenv() + for (Map.Entry change : _environmentChanges.entrySet()) { + if (change.getValue() == null) { + pb.environment().remove(change.getKey()); + } else { + pb.environment().put(change.getKey(), change.getValue()); + } + } + // Run the process with redirected input and error streams. + debugCommand(pb); _process = pb.start(); - debugCommand(); // handle stdout and stderr OutputMonitor stdoutMonitor = new OutputMonitor(_process.getInputStream()); stdoutMonitor.start(); @@ -349,21 +375,15 @@ private void destroy() { /** * Lists the submitted command (if so indicated) */ - private void debugCommand() { + private void debugCommand(ProcessBuilder pb) { if (isDebug()) { - String[] command = getCommand(); - if (command != null) { - System.out.print("[ChildProcess] command '"); - for (int i = 0; i < command.length; i++) { - String commandPart = command[i]; - if (i == 0) { - System.out.print(commandPart); - } else { - System.out.print(" " + commandPart); - } - } - System.out.println("' is now running..."); - } + System.out.print("[ChildProcess] command = "); + System.out.println(pb.command()); + System.out.print("[ChildProcess] environment = "); + System.out.println(pb.environment()); + System.out.print("[ChildProcess] working directory = "); + System.out.println(pb.directory()); } } -} \ No newline at end of file +} + diff --git a/installer/src/java/org/python/util/install/JarInstaller.java b/installer/src/java/org/python/util/install/JarInstaller.java index 76daaae43..30ae6d71d 100644 --- a/installer/src/java/org/python/util/install/JarInstaller.java +++ b/installer/src/java/org/python/util/install/JarInstaller.java @@ -49,7 +49,7 @@ public JarInstaller(ProgressListener progressListener, JarInfo jarInfo) { *
  • generate the start scripts *
  • run ensurepip if selected * - * + * * @param targetDirectory * @param installationType */ @@ -102,8 +102,9 @@ public void inflate(final File targetDirectory, InstallationType installationTyp } } // exclude build.xml when not installing source - if (!installationType.installSources() && zipEntryName.equals("build.xml")) + if (!installationType.installSources() && zipEntryName.equals("build.xml")) { exclude = true; + } // handle exclusion of core Lib files if (!exclude) { exclude = shouldExcludeFile(installationType, @@ -182,12 +183,14 @@ private int ensurepip(Path bindir) { try { String command[]; if (Installation.isWindows()) { - command = new String[]{ bindir.resolve("jython.exe").toString(), "-m", "ensurepip" }; + command = new String[] {bindir.resolve("jython.exe").toString(), "-m", "ensurepip"}; } else { - command = new String[]{ Paths.get(".", "jython").toString(), "-m", "ensurepip"}; + command = new String[] {Paths.get(".", "jython").toString(), "-m", "ensurepip"}; } ChildProcess childProcess = new ChildProcess(command); childProcess.setCWD(bindir); + // JYTHON_HOME will be wrong if set: see https://bugs.jython.org/issue2345 + childProcess.putEnvironment("JYTHON_HOME", null); errorCode = childProcess.run(); } catch (Throwable t) { errorCode = 1; diff --git a/installer/src/java/org/python/util/install/StartScriptGenerator.java b/installer/src/java/org/python/util/install/StartScriptGenerator.java index 3165e6b40..fe0a4c9ea 100644 --- a/installer/src/java/org/python/util/install/StartScriptGenerator.java +++ b/installer/src/java/org/python/util/install/StartScriptGenerator.java @@ -81,7 +81,6 @@ protected final void generateStartScripts() throws IOException { } Files.delete(bindir.resolve("jython.py")); Files.delete(bindir.resolve("jython.exe")); - Files.delete(bindir.resolve("python27.dll")); Files.setPosixFilePermissions(bindir.resolve("jython"), PosixFilePermissions.fromString("rwxr-xr-x")); // 0755 } diff --git a/lib-python/2.7/httplib.py b/lib-python/2.7/httplib.py index 7223ba151..f3bb22c2b 100644 --- a/lib-python/2.7/httplib.py +++ b/lib-python/2.7/httplib.py @@ -242,7 +242,7 @@ # # VCHAR defined in http://tools.ietf.org/html/rfc5234#appendix-B.1 -# the patterns for both name and value are more leniant than RFC +# the patterns for both name and value are more lenient than RFC # definitions to allow for backwards compatibility _is_legal_header_name = re.compile(r'\A[^:\s][^:\r\n]*\Z').match _is_illegal_header_value = re.compile(r'\n(?![ \t])|\r(?![ \t\n])').search @@ -273,9 +273,8 @@ def readheaders(self): Read header lines up to the entirely blank line that terminates them. The (normally blank) line that ends the headers is skipped, but not - included in the returned list. If a non-header line ends the headers, - (which is an error), an attempt is made to backspace over it; it is - never included in the returned list. + included in the returned list. If an invalid line is found in the + header section, it is skipped, and further lines are processed. The variable self.status is set to the empty string if all went well, otherwise it is an error message. The variable self.headers is a @@ -302,19 +301,17 @@ def readheaders(self): self.status = '' headerseen = "" firstline = 1 - startofline = unread = tell = None - if hasattr(self.fp, 'unread'): - unread = self.fp.unread - elif self.seekable: + tell = None + if not hasattr(self.fp, 'unread') and self.seekable: tell = self.fp.tell while True: if len(hlist) > _MAXHEADERS: raise HTTPException("got more than %d headers" % _MAXHEADERS) if tell: try: - startofline = tell() + tell() except IOError: - startofline = tell = None + tell = None self.seekable = 0 line = self.fp.readline(_MAXLINE + 1) if len(line) > _MAXLINE: @@ -345,26 +342,14 @@ def readheaders(self): # It's a legal header line, save it. hlist.append(line) self.addheader(headerseen, line[len(headerseen)+1:].strip()) - continue elif headerseen is not None: # An empty header name. These aren't allowed in HTTP, but it's # probably a benign mistake. Don't add the header, just keep # going. - continue + pass else: - # It's not a header line; throw it back and stop here. - if not self.dict: - self.status = 'No headers' - else: - self.status = 'Non-header line where header expected' - # Try to undo the read. - if unread: - unread(line) - elif tell: - self.fp.seek(startofline) - else: - self.status = self.status + '; bad seek' - break + # It's not a header line; skip it and try the next line. + self.status = 'Non-header line where header expected' class HTTPResponse: diff --git a/lib-python/2.7/test/selfsigned_pythontestdotnet.pem b/lib-python/2.7/test/selfsigned_pythontestdotnet.pem new file mode 100644 index 000000000..2b1760747 --- /dev/null +++ b/lib-python/2.7/test/selfsigned_pythontestdotnet.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIIF9zCCA9+gAwIBAgIUH98b4Fw/DyugC9cV7VK7ZODzHsIwDQYJKoZIhvcNAQEL +BQAwgYoxCzAJBgNVBAYTAlhZMRcwFQYDVQQIDA5DYXN0bGUgQW50aHJheDEYMBYG +A1UEBwwPQXJndW1lbnQgQ2xpbmljMSMwIQYDVQQKDBpQeXRob24gU29mdHdhcmUg +Rm91bmRhdGlvbjEjMCEGA1UEAwwac2VsZi1zaWduZWQucHl0aG9udGVzdC5uZXQw +HhcNMTkwNTA4MDEwMjQzWhcNMjcwNzI0MDEwMjQzWjCBijELMAkGA1UEBhMCWFkx +FzAVBgNVBAgMDkNhc3RsZSBBbnRocmF4MRgwFgYDVQQHDA9Bcmd1bWVudCBDbGlu +aWMxIzAhBgNVBAoMGlB5dGhvbiBTb2Z0d2FyZSBGb3VuZGF0aW9uMSMwIQYDVQQD +DBpzZWxmLXNpZ25lZC5weXRob250ZXN0Lm5ldDCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMKdJlyCThkahwoBb7pl5q64Pe9Fn5jrIvzsveHTc97TpjV2 +RLfICnXKrltPk/ohkVl6K5SUZQZwMVzFubkyxE0nZPHYHlpiKWQxbsYVkYv01rix +IFdLvaxxbGYke2jwQao31s4o61AdlsfK1SdpHQUynBBMssqI3SB4XPmcA7e+wEEx +jxjVish4ixA1vuIZOx8yibu+CFCf/geEjoBMF3QPdzULzlrCSw8k/45iZCSoNbvK +DoL4TVV07PHOxpheDh8ZQmepGvU6pVqhb9m4lgmV0OGWHgozd5Ur9CbTVDmxIEz3 +TSoRtNJK7qtyZdGNqwjksQxgZTjM/d/Lm/BJG99AiOmYOjsl9gbQMZgvQmMAtUsI +aMJnQuZ6R+KEpW/TR5qSKLWZSG45z/op+tzI2m+cE6HwTRVAWbcuJxcAA55MZjqU +OOOu3BBYMjS5nf2sQ9uoXsVBFH7i0mQqoW1SLzr9opI8KsWwFxQmO2vBxWYaN+lH +OmwBZBwyODIsmI1YGXmTp09NxRYz3Qe5GCgFzYowpMrcxUC24iduIdMwwhRM7rKg +7GtIWMSrFfuI1XCLRmSlhDbhNN6fVg2f8Bo9PdH9ihiIyxSrc+FOUasUYCCJvlSZ +8hFUlLvcmrZlWuazohm0lsXuMK1JflmQr/DA/uXxP9xzFfRy+RU3jDyxJbRHAgMB +AAGjUzBRMB0GA1UdDgQWBBSQJyxiPMRK01i+0BsV9zUwDiBaHzAfBgNVHSMEGDAW +gBSQJyxiPMRK01i+0BsV9zUwDiBaHzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4ICAQCR+7a7N/m+WLkxPPIA/CB4MOr2Uf8ixTv435Nyv6rXOun0+lTP +ExSZ0uYQ+L0WylItI3cQHULldDueD+s8TGzxf5woaLKf6tqyr0NYhKs+UeNEzDnN +9PHQIhX0SZw3XyXGUgPNBfRCg2ZDdtMMdOU4XlQN/IN/9hbYTrueyY7eXq9hmtI9 +1srftAMqr9SR1JP7aHI6DVgrEsZVMTDnfT8WmLSGLlY1HmGfdEn1Ip5sbo9uSkiH +AEPgPfjYIvR5LqTOMn4KsrlZyBbFIDh9Sl99M1kZzgH6zUGVLCDg1y6Cms69fx/e +W1HoIeVkY4b4TY7Bk7JsqyNhIuqu7ARaxkdaZWhYaA2YyknwANdFfNpfH+elCLIk +BUt5S3f4i7DaUePTvKukCZiCq4Oyln7RcOn5If73wCeLB/ZM9Ei1HforyLWP1CN8 +XLfpHaoeoPSWIveI0XHUl65LsPN2UbMbul/F23hwl+h8+BLmyAS680Yhn4zEN6Ku +B7Po90HoFa1Du3bmx4jsN73UkT/dwMTi6K072FbipnC1904oGlWmLwvAHvrtxxmL +Pl3pvEaZIu8wa/PNF6Y7J7VIewikIJq6Ta6FrWeFfzMWOj2qA1ZZi6fUaDSNYvuV +J5quYKCc/O+I/yDDf8wyBbZ/gvUXzUHTMYGG+bFrn1p7XDbYYeEJ6R/xEg== +-----END CERTIFICATE----- diff --git a/lib-python/2.7/test/test_httplib.py b/lib-python/2.7/test/test_httplib.py index d3bac0f91..7e8b058e8 100644 --- a/lib-python/2.7/test/test_httplib.py +++ b/lib-python/2.7/test/test_httplib.py @@ -241,6 +241,120 @@ def test_malformed_headers_coped_with(self): self.assertEqual(resp.getheader('First'), 'val') self.assertEqual(resp.getheader('Second'), 'val') + def test_malformed_truncation(self): + # Other malformed header lines, especially without colons, used to + # cause the rest of the header section to be truncated + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'Public-Key-Pins: \n' + b'pin-sha256="xxx=";\n' + b'report-uri="https://..."\r\n' + b'Transfer-Encoding: chunked\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertIsNotNone(resp.getheader('Public-Key-Pins')) + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + def test_blank_line_forms(self): + # Test that both CRLF and LF blank lines can terminate the header + # section and start the body + for blank in (b'\r\n', b'\n'): + resp = b'HTTP/1.1 200 OK\r\n' b'Transfer-Encoding: chunked\r\n' + resp += blank + resp += b'4\r\nbody\r\n0\r\n\r\n' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + resp = b'HTTP/1.0 200 OK\r\n' + blank + b'body' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'body') + + # A blank line ending in CR is not treated as the end of the HTTP + # header section, therefore header fields following it should be + # parsed if possible + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'\r' + b'Name: value\r\n' + b'Transfer-Encoding: chunked\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + # No header fields nor blank line + resp = b'HTTP/1.0 200 OK\r\n' + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'') + + def test_from_line(self): + # The parser handles "From" lines specially, so test this does not + # affect parsing the rest of the header section + resp = ( + b'HTTP/1.1 200 OK\r\n' + b'From start\r\n' + b' continued\r\n' + b'Name: value\r\n' + b'From middle\r\n' + b' continued\r\n' + b'Transfer-Encoding: chunked\r\n' + b'From end\r\n' + b'\r\n' + b'4\r\nbody\r\n0\r\n\r\n' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertIsNotNone(resp.getheader('Name')) + self.assertEqual(resp.getheader('Transfer-Encoding'), 'chunked') + self.assertEqual(resp.read(), b'body') + + resp = ( + b'HTTP/1.0 200 OK\r\n' + b'From alone\r\n' + b'\r\n' + b'body' + ) + resp = httplib.HTTPResponse(FakeSocket(resp)) + resp.begin() + self.assertEqual(resp.read(), b'body') + + def test_parse_all_octets(self): + # Ensure no valid header field octet breaks the parser + body = ( + b'HTTP/1.1 200 OK\r\n' + b"!#$%&'*+-.^_`|~: value\r\n" # Special token characters + b'VCHAR: ' + bytearray(range(0x21, 0x7E + 1)) + b'\r\n' + b'obs-text: ' + bytearray(range(0x80, 0xFF + 1)) + b'\r\n' + b'obs-fold: text\r\n' + b' folded with space\r\n' + b'\tfolded with tab\r\n' + b'Content-Length: 0\r\n' + b'\r\n' + ) + sock = FakeSocket(body) + resp = httplib.HTTPResponse(sock) + resp.begin() + self.assertEqual(resp.getheader('Content-Length'), '0') + self.assertEqual(resp.getheader("!#$%&'*+-.^_`|~"), 'value') + vchar = ''.join(map(chr, range(0x21, 0x7E + 1))) + self.assertEqual(resp.getheader('VCHAR'), vchar) + self.assertIsNotNone(resp.getheader('obs-text')) + folded = resp.getheader('obs-fold') + self.assertTrue(folded.startswith('text')) + self.assertIn(' folded with space', folded) + self.assertTrue(folded.endswith('folded with tab')) + def test_invalid_headers(self): conn = httplib.HTTPConnection('example.com') conn.sock = FakeSocket('') @@ -525,7 +639,7 @@ def test_filenoattr(self): self.assertTrue(hasattr(resp,'fileno'), 'HTTPResponse should expose a fileno attribute') - # Test lines overflowing the max line size (_MAXLINE in http.client) + # Test lines overflowing the max line size (_MAXLINE in httplib) def test_overflowing_status_line(self): self.skipTest("disabled for HTTP 0.9 support") @@ -624,7 +738,7 @@ def testHTTPConnectionSourceAddress(self): def testHTTPSConnectionSourceAddress(self): self.conn = httplib.HTTPSConnection(HOST, self.port, source_address=('', self.source_port)) - # We don't test anything here other the constructor not barfing as + # We don't test anything here other than the constructor not barfing as # this code doesn't deal with setting up an active running SSL server # for an ssl_wrapped connect() to actually return from. diff --git a/lib-python/2.7/urllib.py b/lib-python/2.7/urllib.py index c3ba2c94c..7f70496b6 100644 --- a/lib-python/2.7/urllib.py +++ b/lib-python/2.7/urllib.py @@ -138,7 +138,7 @@ def __init__(self, proxies=None, context=None, **x509): self.key_file = x509.get('key_file') self.cert_file = x509.get('cert_file') self.context = context - self.addheaders = [('User-Agent', self.version)] + self.addheaders = [('User-Agent', self.version), ('Accept', '*/*')] self.__tempfiles = [] self.__unlink = os.unlink # See cleanup() self.tempcache = None diff --git a/lib-python/LICENSE.txt b/lib-python/LICENSE.txt new file mode 100644 index 000000000..bd13df28c --- /dev/null +++ b/lib-python/LICENSE.txt @@ -0,0 +1,748 @@ +A. HISTORY OF THE SOFTWARE +========================== + +Python was created in the early 1990s by Guido van Rossum at Stichting +Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands +as a successor of a language called ABC. Guido remains Python's +principal author, although it includes many contributions from others. + +In 1995, Guido continued his work on Python at the Corporation for +National Research Initiatives (CNRI, see http://www.cnri.reston.va.us) +in Reston, Virginia where he released several versions of the +software. + +In May 2000, Guido and the Python core development team moved to +BeOpen.com to form the BeOpen PythonLabs team. In October of the same +year, the PythonLabs team moved to Digital Creations, which became +Zope Corporation. In 2001, the Python Software Foundation (PSF, see +https://www.python.org/psf/) was formed, a non-profit organization +created specifically to own Python-related Intellectual Property. +Zope Corporation was a sponsoring member of the PSF. + +All Python releases are Open Source (see http://www.opensource.org for +the Open Source Definition). Historically, most, but not all, Python +releases have also been GPL-compatible; the table below summarizes +the various releases. + + Release Derived Year Owner GPL- + from compatible? (1) + + 0.9.0 thru 1.2 1991-1995 CWI yes + 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes + 1.6 1.5.2 2000 CNRI no + 2.0 1.6 2000 BeOpen.com no + 1.6.1 1.6 2001 CNRI yes (2) + 2.1 2.0+1.6.1 2001 PSF no + 2.0.1 2.0+1.6.1 2001 PSF yes + 2.1.1 2.1+2.0.1 2001 PSF yes + 2.1.2 2.1.1 2002 PSF yes + 2.1.3 2.1.2 2002 PSF yes + 2.2 and above 2.1.1 2001-now PSF yes + +Footnotes: + +(1) GPL-compatible doesn't mean that we're distributing Python under + the GPL. All Python licenses, unlike the GPL, let you distribute + a modified version without making your changes open source. The + GPL-compatible licenses make it possible to combine Python with + other software that is released under the GPL; the others don't. + +(2) According to Richard Stallman, 1.6.1 is not GPL-compatible, + because its license has a choice of law clause. According to + CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1 + is "not incompatible" with the GPL. + +Thanks to the many outside volunteers who have worked under Guido's +direction to make these releases possible. + + +B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON +=============================================================== + +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the Internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the Internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +Additional Conditions for this Windows binary build +--------------------------------------------------- + +This program is linked with and uses Microsoft Distributable Code, +copyrighted by Microsoft Corporation. The Microsoft Distributable Code +includes the following files: + +msvcr90.dll +msvcp90.dll +msvcm90.dll + +If you further distribute programs that include the Microsoft +Distributable Code, you must comply with the restrictions on +distribution specified by Microsoft. In particular, you must require +distributors and external end users to agree to terms that protect the +Microsoft Distributable Code at least as much as Microsoft's own +requirements for the Distributable Code. See Microsoft's documentation +(included in its developer tools and on its website at microsoft.com) +for specific details. + +Redistribution of the Windows binary build of the Python interpreter +complies with this agreement, provided that you do not: + +- alter any copyright, trademark or patent notice in Microsoft's +Distributable Code; + +- use Microsoft's trademarks in your programs' names or in a way that +suggests your programs come from or are endorsed by Microsoft; + +- distribute Microsoft's Distributable Code to run on a platform other +than Microsoft operating systems, run-time technologies or application +platforms; or + +- include Microsoft Distributable Code in malicious, deceptive or +unlawful programs. + +These restrictions apply only to the Microsoft Distributable Code as +defined above, not to Python itself or any programs running on the +Python interpreter. The redistribution of the Python interpreter and +libraries is governed by the Python Software License included with this +file, or by other licenses as marked. + + +This copy of Python includes a copy of bzip2, which is licensed under the following terms: + + +-------------------------------------------------------------------------- + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2010 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.6 of 6 September 2010 + +-------------------------------------------------------------------------- + +This copy of Python includes a copy of Berkeley DB, which is licensed under the following terms: + +/*- + * $Id: LICENSE,v 12.9 2008/02/07 17:12:17 mark Exp $ + */ + +The following is the license that applies to this copy of the Berkeley DB +software. For a license to use the Berkeley DB software under conditions +other than those described here, or to purchase support for this software, +please contact Oracle at berkeleydb-info_us@oracle.com. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/* + * Copyright (c) 1990,2008 Oracle. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Redistributions in any form must be accompanied by information on + * how to obtain complete source code for the DB software and any + * accompanying software that uses the DB software. The source code + * must either be included in the distribution or be available for no + * more than the cost of distribution plus a nominal fee, and must be + * freely redistributable under reasonable conditions. For an + * executable file, complete source code means the source code for all + * modules it contains. It does not include source code for modules or + * files that typically accompany the major components of the operating + * system on which the executable file runs. + * + * THIS SOFTWARE IS PROVIDED BY ORACLE ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR + * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL ORACLE BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +/* + * Copyright (c) 1990, 1993, 1994, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* + * Copyright (c) 1995, 1996 + * The President and Fellows of Harvard University. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY HARVARD AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL HARVARD OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= +/*** + * ASM: a very small and fast Java bytecode manipulation framework + * Copyright (c) 2000-2005 INRIA, France Telecom + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +This copy of Python includes a copy of openssl, which is licensed under the following terms: + + + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. Actually both licenses are BSD-style + Open Source licenses. In case of any license issues related to OpenSSL + please contact openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2018 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +This copy of Python includes a copy of Tcl, which is licensed under the following terms: + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState +Corporation and other parties. The following terms apply to all files +associated with the software unless explicitly disclaimed in +individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +This copy of Python includes a copy of Tk, which is licensed under the following terms: + +This software is copyrighted by the Regents of the University of +California, Sun Microsystems, Inc., and other parties. The following +terms apply to all files associated with the software unless explicitly +disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (b) (3) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +This copy of Python includes a copy of Tix, which is licensed under the following terms: + +Copyright (c) 1993-1999 Ioi Kim Lam. +Copyright (c) 2000-2001 Tix Project Group. +Copyright (c) 2004 ActiveState + +This software is copyrighted by the above entities +and other parties. The following terms apply to all files associated +with the software unless explicitly disclaimed in individual files. + +The authors hereby grant permission to use, copy, modify, distribute, +and license this software and its documentation for any purpose, provided +that existing copyright notices are retained in all copies and that this +notice is included verbatim in any distributions. No written agreement, +license, or royalty fee is required for any of the authorized uses. +Modifications to this software may be copyrighted by their authors +and need not follow the licensing terms described here, provided that +the new terms are clearly indicated on the first page of each file where +they apply. + +IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY +FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY +DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE +IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE +NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR +MODIFICATIONS. + +GOVERNMENT USE: If you are acquiring this software on behalf of the +U.S. government, the Government shall have only "Restricted Rights" +in the software and related documentation as defined in the Federal +Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you +are acquiring the software on behalf of the Department of Defense, the +software shall be classified as "Commercial Computer Software" and the +Government shall have only "Restricted Rights" as defined in Clause +252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the +authors grant the U.S. Government and others acting in its behalf +permission to use and distribute the software in accordance with the +terms specified in this license. + +---------------------------------------------------------------------- + +Parts of this software are based on the Tcl/Tk software copyrighted by +the Regents of the University of California, Sun Microsystems, Inc., +and other parties. The original license terms of the Tcl/Tk software +distribution is included in the file docs/license.tcltk. + +Parts of this software are based on the HTML Library software +copyrighted by Sun Microsystems, Inc. The original license terms of +the HTML Library software distribution is included in the file +docs/license.html_lib. diff --git a/maven/build.xml b/maven/build.xml index e33640485..eea24cd06 100644 --- a/maven/build.xml +++ b/maven/build.xml @@ -8,7 +8,7 @@ to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at - + http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, @@ -29,184 +29,221 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/maven/pom-template.xml b/maven/pom-template.xml index a427eaca4..ca981b9b7 100644 --- a/maven/pom-template.xml +++ b/maven/pom-template.xml @@ -9,29 +9,33 @@ jar Jython @PROJECT-VERSION@ - http://www.jython.org/ + https://www.jython.org/ + Jython is an implementation of the high-level, dynamic, object-oriented language Python written in 100% Pure Java, and seamlessly integrated with the Java platform. It thus allows you to run Python on any Java platform. + Jython Software License - http://www.jython.org/Project/license.html + https://www.jython.org/Project/license.html repo + - scm:hg:http://hg.python.org/jython + scm:hg:https://hg.python.org/jython scm:hg:ssh://hg@hg.python.org/jython - http://hg.python.org/jython + https://hg.python.org/jython - + - fwierzbicki - Frank Wierzbicki + jython + Jython Developers + jython-dev@lists.sourceforge.net diff --git a/registry b/registry index b7b54cbe0..8024bfefc 100644 --- a/registry +++ b/registry @@ -1,6 +1,10 @@ # Python Registry -*- sh -*- # This default registry sets many common options to their default values # All of these settings could be erased with no change in behavior +# +# Definitive descriptions of supported keys and values is in the javadoc +# for org.python.core.RegistryKey +# # This is how Jim sets his path on his Windows development machine #python.path=.;c:\\Jython\\Lib;d:\\Python-1.5.2\\Lib @@ -10,29 +14,34 @@ #python.path = d:\\python20\\lib # Set the directory to use for caches (currently just package information) -# This directory should be writable by the user -# If this is an absolute path it is used as given -# Otherwise it is interpreted relative to sys.prefix -# (typically the directory of this file) -python.cachedir = cachedir +# This directory should be writable by the user. If this is an absolute path it is used as given, +# otherwise it is interpreted relative to the current working directory (at initialisation). +#python.cachedir = .jython_cache # Setting this property to true disables the package scan for the cachedir. # Please be aware that disabling this will break importing * from java packages #python.cachedir.skip = false # Properties to check for initializing and updating the package cache -# Hopefully you won't have any need to change these -python.packages.paths = java.class.path, sun.boot.class.path -python.packages.directories = java.ext.dirs +# Values shown here are those hard-coded in Jython's cache manager. + +# Treat JARs on the classpath and (up to Java 8) in the JRE as a source of Python packages. +#python.packages.paths = java.class.path, sun.boot.class.path # up to Java 8 +#python.packages.paths = java.class.path # from Java 9 +# Treat installed optional (Java) packages as source of Python packages (before Java 9) +#python.packages.directories = java.ext.dirs # up to Java 8 +#python.packages.directories # undefined from Java 9 -# Set verbosity to error, warning, message, comment, or debug -# for varying levels of informative messages from Jython. Normally -# this option is set from the command line. + +# DEPRECATED way to set the verbosity of messages output by Jython. If +# specified, "python.verbose" will set logging level for "org.python" when +# the runtime is initialised. It is better to use java.util.logging +# preferences (and the -v option) which work from the start of execution. #python.verbose = message # Jython ships with a JLine console (http://jline.sourceforge.net/) out of the # box. This is selected by default in the Jython command-line application -# (org.python.util,jython) if you do not define python.console to be another +# (org.python.util.jython) if you do not define python.console to be another # class on the command line. Alternatively, you could set python.console here, # but be aware that this will also affect the console in applications that # embed a PythonInterpreter, or use Jython as a JSR-223 script engine. @@ -58,6 +67,14 @@ python.security.respectJavaAccessibility = true # behaviour. python.options.caseok = false +# Setting this non-empty will drop the interpreter into an interactive session at the end of +# execution, like adding the -i flag (roughly) or setting the environment variable PYTHONINSPECT +# during execution. +#python.inspect = true + +# Setting this to a file name will cause that file to be run at the start of each interactive +# session (but not when dropping in with the -i flag in after a script has run). +#python.startup = jython-startup.py # Use this registry entry to control the list of builtin modules; you # can add, remove, or override builtin modules. The value for this diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 000000000..69e01717d --- /dev/null +++ b/settings.gradle @@ -0,0 +1,5 @@ +/* + * Gradle settings for Jython. See also build.gradle. + */ + +rootProject.name = 'jython-slim' diff --git a/src/com/ziclix/python/sql/DataHandler.java b/src/com/ziclix/python/sql/DataHandler.java index c9172a3a3..62efb0fe3 100644 --- a/src/com/ziclix/python/sql/DataHandler.java +++ b/src/com/ziclix/python/sql/DataHandler.java @@ -331,14 +331,14 @@ public PyObject getPyObject(ResultSet set, int col, int type) throws SQLExceptio throw createUnsupportedTypeSQLException("STRUCT", col); default : - throw createUnsupportedTypeSQLException(new Integer(type), col); + throw createUnsupportedTypeSQLException(Integer.valueOf(type), col); } return set.wasNull() || obj == null ? Py.None : obj; } protected final SQLException createUnsupportedTypeSQLException(Object type, int col) { - Object[] vals = {type, new Integer(col)}; + Object[] vals = {type, Integer.valueOf(col)}; String msg = zxJDBC.getString("unsupportedTypeForColumn", vals); return new SQLException(msg); } diff --git a/src/com/ziclix/python/sql/DateFactory.java b/src/com/ziclix/python/sql/DateFactory.java index 5a4f03d28..186159fd5 100644 --- a/src/com/ziclix/python/sql/DateFactory.java +++ b/src/com/ziclix/python/sql/DateFactory.java @@ -19,33 +19,33 @@ public interface DateFactory { /** * This function constructs an object holding a date value. * - * @param year - * @param month - * @param day - * @return PyObject + * @param year to set + * @param month to set + * @param day to set + * @return date as PyObject */ public PyObject Date(int year, int month, int day); /** * This function constructs an object holding a time value. * - * @param hour - * @param minute - * @param second - * @return PyObject + * @param hour to set + * @param minute to set + * @param second to set + * @return time as PyObject */ public PyObject Time(int hour, int minute, int second); /** * This function constructs an object holding a time stamp value. * - * @param year - * @param month - * @param day - * @param hour - * @param minute - * @param second - * @return PyObject + * @param year to set + * @param month to set + * @param day to set + * @param hour to set + * @param minute to set + * @param second to set + * @return time stamp as PyObject */ public PyObject Timestamp(int year, int month, int day, int hour, int minute, int second); @@ -53,7 +53,7 @@ public interface DateFactory { * This function constructs an object holding a date value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in @@ -68,7 +68,7 @@ public interface DateFactory { * This function constructs an object holding a time value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in @@ -83,7 +83,7 @@ public interface DateFactory { * This function constructs an object holding a time stamp value from * the given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in diff --git a/src/com/ziclix/python/sql/Fetch.java b/src/com/ziclix/python/sql/Fetch.java index 6610f48bd..b6ea69289 100644 --- a/src/com/ziclix/python/sql/Fetch.java +++ b/src/com/ziclix/python/sql/Fetch.java @@ -31,14 +31,14 @@ /** *

    The responsibility of a Fetch instance is to manage the iteration of a * ResultSet. Two different alogorithms are available: static or dynamic.

    - *

    + * *

    Static The static variety iterates the entire set immediately, * creating the necessary Jython objects and storing them. It is able to * immediately close the ResultSet so a call to close() is essentially a no-op * from a database resource perspective (it does clear the results list however). * This approach also allows for the correct rowcount to be determined since * the entire result set has been iterated.

    - *

    + * *

    Dynamic The dynamic variety iterates the result set only as requested. * This holds a bit truer to the intent of the API as the fetch*() methods actually * fetch when instructed. This is especially useful for managing exeedingly large @@ -54,7 +54,7 @@ abstract public class Fetch implements Traverseproc { /** * The total number of rows in the result set. - *

    + *

    * Note: since JDBC provides no means to get this information without iterating * the entire result set, only those fetches which build the result statically * will have an accurate row count. @@ -157,7 +157,7 @@ abstract public void add(CallableStatement callableStatement, Procedure procedur /** * Fetch the next row of a query result set, returning a single sequence, * or None when no more data is available. - *

    + *

    * An Error (or subclass) exception is raised if the previous call to * executeXXX() did not produce any result set or no call was issued yet. * @@ -178,7 +178,7 @@ public PyObject fetchone() { * Fetch all (remaining) rows of a query result, returning them as a sequence * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute * can affect the performance of this operation. - *

    + *

    * An Error (or subclass) exception is raised if the previous call to executeXXX() * did not produce any result set or no call was issued yet. * @@ -190,16 +190,16 @@ public PyObject fetchone() { * Fetch the next set of rows of a query result, returning a sequence of * sequences (e.g. a list of tuples). An empty sequence is returned when * no more rows are available. - *

    + *

    * The number of rows to fetch per call is specified by the parameter. If * it is not given, the cursor's arraysize determines the number of rows * to be fetched. The method should try to fetch as many rows as indicated * by the size parameter. If this is not possible due to the specified number * of rows not being available, fewer rows may be returned. - *

    + *

    * An Error (or subclass) exception is raised if the previous call to executeXXX() * did not produce any result set or no call was issued yet. - *

    + *

    * Note there are performance considerations involved with the size parameter. * For optimal performance, it is usually best to use the arraysize attribute. * If the size parameter is used, then it is best for it to retain the same value @@ -219,15 +219,15 @@ public PyObject fetchone() { /** * Scroll the cursor in the result set to a new position according * to mode. - *

    + *

    * If mode is 'relative' (default), value is taken as offset to * the current position in the result set, if set to 'absolute', * value states an absolute target position. - *

    + *

    * An IndexError should be raised in case a scroll operation would * leave the result set. In this case, the cursor position is left * undefined (ideal would be to not move the cursor at all). - *

    + *

    * Note: This method should use native scrollable cursors, if * available, or revert to an emulation for forward-only * scrollable cursors. The method may raise NotSupportedErrors to @@ -248,9 +248,9 @@ public void close() throws SQLException { /** * Builds a tuple containing the meta-information about each column. - *

    + *

    * (name, type_code, display_size, internal_size, precision, scale, null_ok) - *

    + *

    * precision and scale are only available for numeric types */ protected PyObject createDescription(ResultSetMetaData meta) throws SQLException { @@ -293,9 +293,9 @@ protected PyObject createDescription(ResultSetMetaData meta) throws SQLException /** * Builds a tuple containing the meta-information about each column. - *

    + *

    * (name, type_code, display_size, internal_size, precision, scale, null_ok) - *

    + *

    * precision and scale are only available for numeric types */ protected PyObject createDescription(Procedure procedure) throws SQLException { @@ -617,7 +617,7 @@ public void add(CallableStatement callableStatement, Procedure procedure, PyObje * Fetch all (remaining) rows of a query result, returning them as a sequence * of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute * can affect the performance of this operation. - *

    + *

    * An Error (or subclass) exception is raised if the previous call to executeXXX() * did not produce any result set or no call was issued yet. * @@ -633,16 +633,16 @@ public PyObject fetchall() { * Fetch the next set of rows of a query result, returning a sequence of * sequences (e.g. a list of tuples). An empty sequence is returned when * no more rows are available. - *

    + *

    * The number of rows to fetch per call is specified by the parameter. If * it is not given, the cursor's arraysize determines the number of rows * to be fetched. The method should try to fetch as many rows as indicated * by the size parameter. If this is not possible due to the specified number * of rows not being available, fewer rows may be returned. - *

    + *

    * An Error (or subclass) exception is raised if the previous call to executeXXX() * did not produce any result set or no call was issued yet. - *

    + *

    * Note there are performance considerations involved with the size parameter. * For optimal performance, it is usually best to use the arraysize attribute. * If the size parameter is used, then it is best for it to retain the same value diff --git a/src/com/ziclix/python/sql/JavaDateFactory.java b/src/com/ziclix/python/sql/JavaDateFactory.java index a89341824..dfce74121 100644 --- a/src/com/ziclix/python/sql/JavaDateFactory.java +++ b/src/com/ziclix/python/sql/JavaDateFactory.java @@ -1,10 +1,9 @@ +// Copyright (c)2019 Jython Developers /* * Jython Database Specification API 2.0 - * - * - * Copyright (c) 2003 brian zimmer - * + * Copyright (c) 2001 brian zimmer */ +// Licensed to the PSF under a Contributor Agreement package com.ziclix.python.sql; import org.python.core.Py; @@ -24,11 +23,12 @@ public class JavaDateFactory implements DateFactory { /** * This function constructs an object holding a date value. * - * @param year - * @param month - * @param day - * @return PyObject + * @param year to set + * @param month to set + * @param day to set + * @return date as PyObject */ + @Override public PyObject Date(int year, int month, int day) { Calendar c = Calendar.getInstance(); @@ -43,11 +43,12 @@ public PyObject Date(int year, int month, int day) { /** * This function constructs an object holding a time value. * - * @param hour - * @param minute - * @param second - * @return PyObject + * @param hour to set + * @param minute to set + * @param second to set + * @return time as PyObject */ + @Override public PyObject Time(int hour, int minute, int second) { Calendar c = Calendar.getInstance(); @@ -62,14 +63,15 @@ public PyObject Time(int hour, int minute, int second) { /** * This function constructs an object holding a time stamp value. * - * @param year - * @param month - * @param day - * @param hour - * @param minute - * @param second - * @return PyObject + * @param year to set + * @param month to set + * @param day to set + * @param hour to set + * @param minute to set + * @param second to set + * @return time stamp as PyObject */ + @Override public PyObject Timestamp(int year, int month, int day, int hour, int minute, int second) { Calendar c = Calendar.getInstance(); @@ -89,7 +91,7 @@ public PyObject Timestamp(int year, int month, int day, int hour, int minute, in * This function constructs an object holding a date value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in @@ -98,6 +100,7 @@ public PyObject Timestamp(int year, int month, int day, int hour, int minute, in * @param ticks number of seconds since the epoch * @return PyObject */ + @Override public PyObject DateFromTicks(long ticks) { Calendar c = Calendar.getInstance(); @@ -115,7 +118,7 @@ public PyObject DateFromTicks(long ticks) { * This function constructs an object holding a time value from the * given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in @@ -124,6 +127,7 @@ public PyObject DateFromTicks(long ticks) { * @param ticks number of seconds since the epoch * @return PyObject */ + @Override public PyObject TimeFromTicks(long ticks) { return Py.java2py(new Time(ticks * 1000)); } @@ -132,7 +136,7 @@ public PyObject TimeFromTicks(long ticks) { * This function constructs an object holding a time stamp value from * the given ticks value (number of seconds since the epoch; see the * documentation of the standard Python time module for details). - *

    + *

    * Note: The DB API 2.0 spec calls for time in seconds since the epoch * while the Java Date object returns time in milliseconds since the epoch. * This module adheres to the python API and will therefore use time in @@ -141,6 +145,7 @@ public PyObject TimeFromTicks(long ticks) { * @param ticks number of seconds since the epoch * @return PyObject */ + @Override public PyObject TimestampFromTicks(long ticks) { return Py.java2py(new Timestamp(ticks * 1000)); } diff --git a/src/com/ziclix/python/sql/Jython22DataHandler.java b/src/com/ziclix/python/sql/Jython22DataHandler.java index 4fb6aaa5c..79a86743f 100644 --- a/src/com/ziclix/python/sql/Jython22DataHandler.java +++ b/src/com/ziclix/python/sql/Jython22DataHandler.java @@ -313,7 +313,7 @@ public PyObject getPyObject(ResultSet set, int col, int type) throws SQLExceptio break; default : - throw createUnsupportedTypeSQLException(new Integer(type), col); + throw createUnsupportedTypeSQLException(Integer.valueOf(type), col); } return (set.wasNull() || (obj == null)) ? Py.None : obj; @@ -401,7 +401,7 @@ public PyObject getPyObject(CallableStatement stmt, int col, int type) throws SQ break; default : - throw createUnsupportedTypeSQLException(new Integer(type), col); + throw createUnsupportedTypeSQLException(Integer.valueOf(type), col); } return (stmt.wasNull() || (obj == null)) ? Py.None : obj; diff --git a/src/com/ziclix/python/sql/Procedure.java b/src/com/ziclix/python/sql/Procedure.java index 789ca3da4..793199fe9 100644 --- a/src/com/ziclix/python/sql/Procedure.java +++ b/src/com/ziclix/python/sql/Procedure.java @@ -235,13 +235,13 @@ public boolean isInput(int index) throws SQLException { } /** - * Returns the call in the syntax: - *

    + * Returns the call in the syntax:

    {@literal
          * {? = call (?, ?, ...)}
          * {call (?, ?, ...)}
    -     * 

    - * As of now, all parameters variables are created and no support for named variable - * calling is supported. + * }

    + * + * As of now, all parameters variables are created and no support for named variable calling is + * supported. * * @return String */ diff --git a/src/com/ziclix/python/sql/PyConnection.java b/src/com/ziclix/python/sql/PyConnection.java index fd9e5d6b8..514362d8d 100644 --- a/src/com/ziclix/python/sql/PyConnection.java +++ b/src/com/ziclix/python/sql/PyConnection.java @@ -273,7 +273,7 @@ public void close() { * Commit any pending transaction to the database. Note that if the database supports * an auto-commit feature, this must be initially off. An interface method may be * provided to turn it back on. - *

    + *

    * Database modules that do not support transactions should implement this method with * void functionality. */ @@ -295,7 +295,7 @@ public void commit() { /** * This method is optional since not all databases provide transaction support. - *

    + *

    * In case a database does provide transactions this method causes the database to * roll back to the start of any pending transaction. Closing a connection without * committing the changes first will cause an implicit rollback to be performed. diff --git a/src/com/ziclix/python/sql/connect/Connectx.java b/src/com/ziclix/python/sql/connect/Connectx.java index ebcd22941..d7d42ea27 100644 --- a/src/com/ziclix/python/sql/connect/Connectx.java +++ b/src/com/ziclix/python/sql/connect/Connectx.java @@ -58,7 +58,7 @@ public PyObject __call__(PyObject[] args, String[] keywords) { try { String klass = (String) parser.arg(0).__tojava__(String.class); - datasource = Class.forName(klass).newInstance(); + datasource = Class.forName(klass).getDeclaredConstructor().newInstance(); } catch (Exception e) { throw zxJDBC.makeException(zxJDBC.DatabaseError, "unable to instantiate datasource"); } @@ -113,11 +113,6 @@ public PyObject __call__(PyObject[] args, String[] keywords) { return pc; } - /** - * Method toString - * - * @return String - */ @Override public String toString() { return String.format("", Py.id(this)); @@ -126,9 +121,9 @@ public String toString() { /** * Method invoke * - * @param Object src - * @param String methodName - * @param Object value + * @param src + * @param methodName + * @param value */ protected void invoke(Object src, String methodName, Object value) { Method method = null; diff --git a/src/com/ziclix/python/sql/handler/RowIdHandler.java b/src/com/ziclix/python/sql/handler/RowIdHandler.java index 74f8211e8..324dda272 100644 --- a/src/com/ziclix/python/sql/handler/RowIdHandler.java +++ b/src/com/ziclix/python/sql/handler/RowIdHandler.java @@ -37,7 +37,7 @@ public RowIdHandler(DataHandler handler) { * Return the name of the method that returns the last row id. The * method can take no arguments but the return type is flexible and * will be figured out by the Jython runtime system. - * @return + * @return name of the method that returns the last row id */ protected abstract String getRowIdMethodName(); @@ -47,7 +47,8 @@ public RowIdHandler(DataHandler handler) { * @return an object representing the last row id * @throws SQLException */ - public PyObject getRowId(Statement stmt) throws SQLException { + @Override +public PyObject getRowId(Statement stmt) throws SQLException { Class c = stmt.getClass(); Object o = ROWIDS.get(c); diff --git a/src/com/ziclix/python/sql/handler/SQLServerDataHandler.java b/src/com/ziclix/python/sql/handler/SQLServerDataHandler.java index b990f16e5..06db6895a 100644 --- a/src/com/ziclix/python/sql/handler/SQLServerDataHandler.java +++ b/src/com/ziclix/python/sql/handler/SQLServerDataHandler.java @@ -47,7 +47,7 @@ public Procedure getProcedure(PyCursor cursor, PyObject name) throws SQLExceptio /** * Given a ResultSet, column and type, return the appropriate * Jython object. - *

    + * *

    Note: DO NOT iterate the ResultSet. * * @param set the current ResultSet set to the current row diff --git a/src/com/ziclix/python/sql/handler/UpdateCountDataHandler.java b/src/com/ziclix/python/sql/handler/UpdateCountDataHandler.java index 12a623d70..f6f4c65b1 100644 --- a/src/com/ziclix/python/sql/handler/UpdateCountDataHandler.java +++ b/src/com/ziclix/python/sql/handler/UpdateCountDataHandler.java @@ -18,7 +18,7 @@ /** * A data handler that keeps track of the update count for each execution of a * Statement. - *

    + * *

    Note: MySql does not return the correct count for a * delete statement that has * no where clause. Therefore, to assure the correct update count is returned, diff --git a/src/com/ziclix/python/sql/pipe/Pipe.java b/src/com/ziclix/python/sql/pipe/Pipe.java index a9dc81c49..6bb95cfe3 100644 --- a/src/com/ziclix/python/sql/pipe/Pipe.java +++ b/src/com/ziclix/python/sql/pipe/Pipe.java @@ -30,7 +30,7 @@ public Pipe() { } /** - * Start the processing of the Source->Sink. + * Start the processing of the Source to the Sink. * * @param source the data generator * @param sink the consumer of the data @@ -87,8 +87,8 @@ public PyObject pipe(Source source, Sink sink) { // the purpose of the assert, but there's no need to create the buffer if I don't need it and I still // want to throw the AssertionError if required if ((sourceRunner.getCount() - sinkRunner.getCount()) != 0) { - Integer[] counts = {new Integer(sourceRunner.getCount()), - new Integer(sinkRunner.getCount())}; + Integer[] counts = {Integer.valueOf(sourceRunner.getCount()), + Integer.valueOf(sinkRunner.getCount())}; String msg = zxJDBC.getString("inconsistentRowCount", counts); Py.assert_(Py.Zero, Py.newString(msg)); @@ -144,6 +144,7 @@ public int getCount() { /** * Method run */ + @Override public void run() { try { @@ -216,6 +217,7 @@ public SourceRunner(Queue queue, Source source) { * * @throws InterruptedException */ + @Override protected void pipe() throws InterruptedException { PyObject row = Py.None; @@ -270,6 +272,7 @@ public SinkRunner(Queue queue, Sink sink) { * * @throws InterruptedException */ + @Override protected void pipe() throws InterruptedException { PyObject row = Py.None; diff --git a/src/com/ziclix/python/sql/pipe/Sink.java b/src/com/ziclix/python/sql/pipe/Sink.java index c0ec6e9d5..322e66455 100644 --- a/src/com/ziclix/python/sql/pipe/Sink.java +++ b/src/com/ziclix/python/sql/pipe/Sink.java @@ -24,9 +24,9 @@ public interface Sink { /** * Invoked for each row of data. In general, the first row of data will - * consist of header information in the format:
    + * consist of header information in the format:
    *   [(colName, colType), ...] - * and in the format:
    + * and in the format:
    *   (colData, colData, ...) * for all other data. */ diff --git a/src/com/ziclix/python/sql/pipe/Source.java b/src/com/ziclix/python/sql/pipe/Source.java index 7a11ccffb..8664280e6 100644 --- a/src/com/ziclix/python/sql/pipe/Source.java +++ b/src/com/ziclix/python/sql/pipe/Source.java @@ -28,7 +28,7 @@ public interface Source { * Return the next row from the source. * The following format:
    *   [(colName, colType), (colName, colType), ...] - * for headers and:
    + * for headers and:
    *   [(col), (colName, colType), ...] * for all other data must be used. */ diff --git a/src/com/ziclix/python/sql/pipe/csv/CSVString.java b/src/com/ziclix/python/sql/pipe/csv/CSVString.java index 1eae3967f..69b0f5098 100644 --- a/src/com/ziclix/python/sql/pipe/csv/CSVString.java +++ b/src/com/ziclix/python/sql/pipe/csv/CSVString.java @@ -44,17 +44,16 @@ public static String toCSV(String string, String delimiter) { } /** - * Returns a new string resulting from replacing the first occurrence, or all occurrences, - * of search string in this string with replace string. - * If the string search does not occur in the character sequence represented by this object, - * then this string is returned. + * Returns a new string resulting from replacing the first occurrence, or all occurrences, of + * search string in this string with replace string. If the string search does not occur in the + * character sequence represented by this object, then this string is returned. * - * @param search the old string - * @param replace the new string - * @param all=true all occurrences of the search string are replaced - * @param all=false only the first occurrence of the search string is replaced - * @return a string derived from this string by replacing the first occurrence, - * or every occurrence of search with replace. + * @param search the old string + * @param replace the new string + * @param all if {@code true} all occurrences of the search string are replaced; if + * {@code false} only the first occurrence + * @return a string derived from this string by replacing the first occurrence, or every + * occurrence, of {@code search} with {@code replace}. */ public static String replace(String original, String search, String replace, boolean all) { diff --git a/src/com/ziclix/python/sql/util/BCP.java b/src/com/ziclix/python/sql/util/BCP.java index 01a5b9ed3..6df774281 100644 --- a/src/com/ziclix/python/sql/util/BCP.java +++ b/src/com/ziclix/python/sql/util/BCP.java @@ -1,10 +1,9 @@ +// Copyright (c)2019 Jython Developers /* * Jython Database Specification API 2.0 - * - * * Copyright (c) 2001 brian zimmer - * */ +// Licensed to the PSF under a Contributor Agreement package com.ziclix.python.sql.util; import org.python.core.ClassDictInit; @@ -68,7 +67,7 @@ public BCP(PyConnection source, PyConnection destination, int batchsize) { this.batchsize = batchsize; this.queuesize = 0; } - + /** * Field __methods__ */ @@ -99,6 +98,7 @@ public BCP(PyConnection source, PyConnection destination, int batchsize) { * * @return a string representation of the object. */ + @Override public String toString() { return ""; } @@ -109,6 +109,7 @@ public String toString() { * @param name * @param value */ + @Override public void __setattr__(String name, PyObject value) { if ("destinationDataHandler".equals(name)) { @@ -130,6 +131,7 @@ public void __setattr__(String name, PyObject value) { * @param name * @return the attribute for the given name */ + @Override public PyObject __findattr_ex__(String name) { if ("destinationDataHandler".equals(name)) { @@ -206,7 +208,7 @@ public boolean refersDirectlyTo(PyObject ob) { } /** - * @copyright 2001 brian zimmer + * Copyright 2001 brian zimmer */ class BCPFunc extends PyBuiltinMethodSet { @@ -224,6 +226,7 @@ class BCPFunc extends PyBuiltinMethodSet { * @param arg * @return PyObject */ + @Override public PyObject __call__(PyObject arg) { BCP bcp = (BCP) __self__; @@ -246,6 +249,7 @@ public PyObject __call__(PyObject arg) { } } + @Override public PyObject __call__(PyObject arga, PyObject argb) { BCP bcp = (BCP) __self__; @@ -269,6 +273,7 @@ public PyObject __call__(PyObject arga, PyObject argb) { } } + @Override public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) { BCP bcp = (BCP) __self__; @@ -292,6 +297,7 @@ public PyObject __call__(PyObject arga, PyObject argb, PyObject argc) { } } + @Override public PyObject __call__(PyObject[] args, String[] keywords) { BCP bcp = (BCP) __self__; diff --git a/src/com/ziclix/python/sql/zxJDBC.java b/src/com/ziclix/python/sql/zxJDBC.java index 3b1a8b3ae..25cd60cec 100644 --- a/src/com/ziclix/python/sql/zxJDBC.java +++ b/src/com/ziclix/python/sql/zxJDBC.java @@ -34,7 +34,7 @@ /** * Creates database connections. - *

    + *

    *

      * from com.ziclix.python.sql import zxJDBC
      * db = zxJDBC.connect("jdbc:mysql://localhost:3306/MySql", None, None, "org.gjt.mm.mysql.Driver")
    @@ -223,7 +223,8 @@ protected static void _addConnectors(PyObject dict) throws PyException {
                 String className = props.getProperty(name).trim();
     
                 try {
    -                connector = (PyObject) Class.forName(className).newInstance();
    +                connector =
    +                        (PyObject) Class.forName(className).getDeclaredConstructor().newInstance();
                     dict.__setitem__(name, connector);
                     Py.writeComment("zxJDBC", "loaded connector [" + className + "] as [" + name
                                     + "]");
    @@ -326,7 +327,7 @@ public static PyException makeException(String msg) {
          * @return PyException
          */
         public static PyException makeException(PyObject type, String msg) {
    -        return Py.makeException(type, msg == null ? Py.EmptyString : Py.newString(msg));
    +        return Py.makeException(type, msg == null ? Py.EmptyString : Py.newStringOrUnicode(msg));
         }
     
         /**
    @@ -419,7 +420,6 @@ public static PyException makeException(PyObject type, Throwable t, int rowIndex
          *
          * @param classname
          * @param superclass
    -     * @param classCodeName
          * @return PyObject
          */
         protected static PyObject buildClass(String classname, PyObject superclass) {
    diff --git a/src/org/python/Version.java b/src/org/python/Version.java
    index e06e16224..e16b0628b 100644
    --- a/src/org/python/Version.java
    +++ b/src/org/python/Version.java
    @@ -121,7 +121,7 @@ public static String getBuildInfo() {
          * Describe the current Java VM.
          */
         public static String getVM() {
    -        return String.format("\n[%s (%s)]", System.getProperty("java.vm.name"),
    +        return String.format("[%s (%s)]", System.getProperty("java.vm.name"),
                                  System.getProperty("java.vm.vendor"));
         }
     
    @@ -130,7 +130,7 @@ public static String getVM() {
          * the Java VM).
          */
         public static String getVersion() {
    -        return String.format("%.80s (%.80s) %.80s", PY_VERSION, getBuildInfo(), getVM());
    +        return String.format("%.80s (%.80s)\n%.80s", PY_VERSION, getBuildInfo(), getVM());
         }
     
         public static Set getDefaultCodeFlags() {
    diff --git a/src/org/python/antlr/ASTDerived.java b/src/org/python/antlr/ASTDerived.java
    new file mode 100644
    index 000000000..f6b2e37a0
    --- /dev/null
    +++ b/src/org/python/antlr/ASTDerived.java
    @@ -0,0 +1,1175 @@
    +/* Generated file, do not modify.  See jython/src/templates/gderived.py. */
    +package org.python.antlr;
    +
    +import java.io.Serializable;
    +import org.python.core.*;
    +import org.python.core.finalization.FinalizeTrigger;
    +import org.python.core.finalization.FinalizablePyObjectDerived;
    +
    +public class ASTDerived extends AST implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived {
    +
    +    public PyObject getSlot(int index) {
    +        return slots[index];
    +    }
    +
    +    public void setSlot(int index,PyObject value) {
    +        slots[index]=value;
    +    }
    +
    +    private PyObject[]slots;
    +
    +    public void __del_derived__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__del__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__();
    +        }
    +    }
    +
    +    public void __ensure_finalizer__() {
    +        FinalizeTrigger.ensureFinalizer(this);
    +    }
    +
    +    /* TraverseprocDerived implementation */
    +    public int traverseDerived(Visitproc visit,Object arg) {
    +        int retVal;
    +        for(int i=0;i0?1:0;
    +    }
    +
    +    public boolean __nonzero__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__nonzero__");
    +        if (impl==null) {
    +            impl=self_type.lookup("__len__");
    +            if (impl==null)
    +                return super.__nonzero__();
    +        }
    +        PyObject o=impl.__get__(this,self_type).__call__();
    +        Class c=o.getClass();
    +        if (c!=PyInteger.class&&c!=PyBoolean.class) {
    +            throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName()));
    +        }
    +        return o.__nonzero__();
    +    }
    +
    +    public boolean __contains__(PyObject o) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__contains__");
    +        if (impl==null)
    +            return super.__contains__(o);
    +        return impl.__get__(this,self_type).__call__(o).__nonzero__();
    +    }
    +
    +    public int __len__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__len__");
    +        if (impl!=null) {
    +            PyObject res=impl.__get__(this,self_type).__call__();
    +            return res.asInt();
    +        }
    +        return super.__len__();
    +    }
    +
    +    public PyObject __iter__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__iter__");
    +        if (impl!=null)
    +            return impl.__get__(this,self_type).__call__();
    +        impl=self_type.lookup("__getitem__");
    +        if (impl==null)
    +            return super.__iter__();
    +        return new PySequenceIter(this);
    +    }
    +
    +    public PyObject __iternext__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("next");
    +        if (impl!=null) {
    +            try {
    +                return impl.__get__(this,self_type).__call__();
    +            } catch (PyException exc) {
    +                if (exc.match(Py.StopIteration))
    +                    return null;
    +                throw exc;
    +            }
    +        }
    +        return super.__iternext__(); // ???
    +    }
    +
    +    public PyObject __finditem__(PyObject key) { // ???
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__getitem__");
    +        if (impl!=null)
    +            try {
    +                return impl.__get__(this,self_type).__call__(key);
    +            } catch (PyException exc) {
    +                if (exc.match(Py.LookupError))
    +                    return null;
    +                throw exc;
    +            }
    +        return super.__finditem__(key);
    +    }
    +
    +    public PyObject __finditem__(int key) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__getitem__");
    +        if (impl!=null)
    +            try {
    +                return impl.__get__(this,self_type).__call__(new PyInteger(key));
    +            } catch (PyException exc) {
    +                if (exc.match(Py.LookupError))
    +                    return null;
    +                throw exc;
    +            }
    +        return super.__finditem__(key);
    +    }
    +
    +    public PyObject __getitem__(PyObject key) {
    +        // Same as __finditem__, without swallowing LookupErrors. This allows
    +        // __getitem__ implementations written in Python to raise custom
    +        // exceptions (such as subclasses of KeyError).
    +        //
    +        // We are forced to duplicate the code, instead of defining __finditem__
    +        // in terms of __getitem__. That's because PyObject defines __getitem__
    +        // in terms of __finditem__. Therefore, we would end with an infinite
    +        // loop when self_type.lookup("__getitem__") returns null:
    +        //
    +        //  __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__
    +        //
    +        // By duplicating the (short) lookup and call code, we are safe, because
    +        // the call chains will be:
    +        //
    +        // __finditem__ -> super.__finditem__
    +        //
    +        // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__
    +
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__getitem__");
    +        if (impl!=null)
    +            return impl.__get__(this,self_type).__call__(key);
    +        return super.__getitem__(key);
    +    }
    +
    +    public void __setitem__(PyObject key,PyObject value) { // ???
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__setitem__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(key,value);
    +            return;
    +        }
    +        super.__setitem__(key,value);
    +    }
    +
    +    public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ???
    +        if (step!=null) {
    +            return __getitem__(new PySlice(start,stop,step));
    +        }
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__getslice__");
    +        if (impl!=null) {
    +            PyObject[]indices=PySlice.indices2(this,start,stop);
    +            return impl.__get__(this,self_type).__call__(indices[0],indices[1]);
    +        }
    +        return super.__getslice__(start,stop,step);
    +    }
    +
    +    public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) {
    +        if (step!=null) {
    +            __setitem__(new PySlice(start,stop,step),value);
    +            return;
    +        }
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__setslice__");
    +        if (impl!=null) {
    +            PyObject[]indices=PySlice.indices2(this,start,stop);
    +            impl.__get__(this,self_type).__call__(indices[0],indices[1],value);
    +            return;
    +        }
    +        super.__setslice__(start,stop,step,value);
    +    }
    +
    +    public void __delslice__(PyObject start,PyObject stop,PyObject step) {
    +        if (step!=null) {
    +            __delitem__(new PySlice(start,stop,step));
    +            return;
    +        }
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__delslice__");
    +        if (impl!=null) {
    +            PyObject[]indices=PySlice.indices2(this,start,stop);
    +            impl.__get__(this,self_type).__call__(indices[0],indices[1]);
    +            return;
    +        }
    +        super.__delslice__(start,stop,step);
    +    }
    +
    +    public void __delitem__(PyObject key) { // ???
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__delitem__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(key);
    +            return;
    +        }
    +        super.__delitem__(key);
    +    }
    +
    +    public PyObject __call__(PyObject args[],String keywords[]) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__call__");
    +        if (impl!=null) {
    +            return impl.__get__(this,self_type).__call__(args,keywords);
    +        }
    +        return super.__call__(args,keywords);
    +    }
    +
    +    public PyObject __findattr_ex__(String name) {
    +        return Deriveds.__findattr_ex__(this,name);
    +    }
    +
    +    public void __setattr__(String name,PyObject value) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__setattr__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value);
    +            //CPython does not support instance-acquired finalizers.
    +            //So we don't check for __del__ here.
    +            return;
    +        }
    +        super.__setattr__(name,value);
    +    }
    +
    +    public void __delattr__(String name) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__delattr__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(PyString.fromInterned(name));
    +            return;
    +        }
    +        super.__delattr__(name);
    +    }
    +
    +    public PyObject __get__(PyObject obj,PyObject type) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__get__");
    +        if (impl!=null) {
    +            if (obj==null)
    +                obj=Py.None;
    +            if (type==null)
    +                type=Py.None;
    +            return impl.__get__(this,self_type).__call__(obj,type);
    +        }
    +        return super.__get__(obj,type);
    +    }
    +
    +    public void __set__(PyObject obj,PyObject value) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__set__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(obj,value);
    +            return;
    +        }
    +        super.__set__(obj,value);
    +    }
    +
    +    public void __delete__(PyObject obj) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__delete__");
    +        if (impl!=null) {
    +            impl.__get__(this,self_type).__call__(obj);
    +            return;
    +        }
    +        super.__delete__(obj);
    +    }
    +
    +    public PyObject __pow__(PyObject other,PyObject modulo) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__pow__");
    +        if (impl!=null) {
    +            PyObject res;
    +            if (modulo==null) {
    +                res=impl.__get__(this,self_type).__call__(other);
    +            } else {
    +                res=impl.__get__(this,self_type).__call__(other,modulo);
    +            }
    +            if (res==Py.NotImplemented)
    +                return null;
    +            return res;
    +        }
    +        return super.__pow__(other,modulo);
    +    }
    +
    +    public void dispatch__init__(PyObject[]args,String[]keywords) {
    +        Deriveds.dispatch__init__(this,args,keywords);
    +    }
    +
    +    public PyObject __index__() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__index__");
    +        if (impl!=null) {
    +            PyObject res=impl.__get__(this,self_type).__call__();
    +            if (res instanceof PyInteger||res instanceof PyLong) {
    +                return res;
    +            }
    +            throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName()));
    +        }
    +        return super.__index__();
    +    }
    +
    +    public Object __tojava__(Class c) {
    +        // If we are not being asked by the "default" conversion to java, then
    +        // we can provide this as the result, as long as it is a instance of the
    +        // specified class. Without this, derived.__tojava__(PyObject.class)
    +        // would broke. (And that's not pure speculation: PyReflectedFunction's
    +        // ReflectedArgs asks for things like that).
    +        if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) {
    +            return this;
    +        }
    +        // Otherwise, we call the derived __tojava__, if it exists:
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__tojava__");
    +        if (impl!=null) {
    +            PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c));
    +            if (delegate!=this)
    +                return delegate.__tojava__(Object.class);
    +        }
    +        return super.__tojava__(c);
    +    }
    +
    +    public Object __coerce_ex__(PyObject o) {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__coerce__");
    +        if (impl!=null) {
    +            PyObject res=impl.__get__(this,self_type).__call__(o);
    +            if (res==Py.NotImplemented)
    +                return Py.None;
    +            if (!(res instanceof PyTuple))
    +                throw Py.TypeError("__coerce__ didn't return a 2-tuple");
    +            return((PyTuple)res).getArray();
    +        }
    +        return super.__coerce_ex__(o);
    +    }
    +
    +    public String toString() {
    +        PyType self_type=getType();
    +        PyObject impl=self_type.lookup("__repr__");
    +        if (impl!=null) {
    +            PyObject res=impl.__get__(this,self_type).__call__();
    +            if (!(res instanceof PyString))
    +                throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")");
    +            return((PyString)res).toString();
    +        }
    +        return super.toString();
    +    }
    +
    +}
    diff --git a/src/org/python/antlr/BaseParser.java b/src/org/python/antlr/BaseParser.java
    index a1c82a3ca..8fd5847c6 100644
    --- a/src/org/python/antlr/BaseParser.java
    +++ b/src/org/python/antlr/BaseParser.java
    @@ -3,7 +3,6 @@
     import org.antlr.runtime.CharStream;
     import org.antlr.runtime.CommonTokenStream;
     import org.antlr.runtime.RecognitionException;
    -import org.antlr.runtime.Token;
     import org.python.antlr.base.mod;
     
     public class BaseParser {
    diff --git a/src/org/python/antlr/GrammarActions.java b/src/org/python/antlr/GrammarActions.java
    index a5c42ce72..14d56c2d3 100644
    --- a/src/org/python/antlr/GrammarActions.java
    +++ b/src/org/python/antlr/GrammarActions.java
    @@ -129,10 +129,10 @@ List makeBases(expr etype) {
             return result;
         }
     
    -    List makeNames(List names) {
    +    List makeNames(List names) {
             List s = new ArrayList();
    -        for(int i=0;i makeNameNodes(List names) {
             List s = new ArrayList();
    -        for (int i=0; i{@literal
      a=1
      if a>1:
          print a
      b=3
    -
    +}
    Here the "b" token on the left edge signals that a DEDENT is needed after the "print a \n" and before the "b". The sequence should be - +
      ... 1 COLON NEWLINE INDENT PRINT a NEWLINE DEDENT b ASSIGN 3 ...
    -
    +
    For more examples, see the big comment at the bottom of this file. This TokenStream normally just passes tokens through to the parser. @@ -131,12 +131,15 @@ public PythonTokenSource(CommonTokenStream stream, String filename, boolean sing EOF to have char pos 0 even though with UNIX it's hard to get EOF at a non left edge. */ + @Override public Token nextToken() { // if something in queue, just remove and return it if (tokens.size() > 0) { Token t = tokens.firstElement(); - tokens.removeElementAt(0); - //System.out.println(filename + t); + if (t.getType() != Token.EOF) { // EOF stops further insertImaginaryIndentDedentTokens + tokens.removeElementAt(0); + } + // System.out.println(filename + t); return t; } @@ -165,7 +168,6 @@ private void handleEOF(CommonToken eof, CommonToken prev) { protected void insertImaginaryIndentDedentTokens() { Token t = stream.LT(1); - stream.consume(); if (t.getType() == Token.EOF) { Token prev = stream.LT(-1); @@ -187,13 +189,12 @@ protected void insertImaginaryIndentDedentTokens() { } else if (t.getType() == PythonLexer.NEWLINE) { // save NEWLINE in the queue //System.out.println("found newline: "+t+" stack is "+stackString()); - enqueueHiddens(t); - tokens.addElement(t); + enqueue(t); Token newline = t; + stream.consume(); // grab first token of next line t = stream.LT(1); - stream.consume(); List commentedNewlines = enqueueHiddens(t); @@ -204,13 +205,15 @@ protected void insertImaginaryIndentDedentTokens() { cpos = -1; // pretend EOF always happens at left edge } else if (t.getType() == PythonLexer.LEADING_WS) { + stream.consume(); Token next = stream.LT(1); if (next != null && next.getType() == Token.EOF) { - stream.consume(); return; } else { cpos = t.getText().length(); } + } else { + stream.consume(); } //System.out.println("next token is: "+t); @@ -241,9 +244,10 @@ else if (cpos < lastIndent) { // they dedented } else { enqueue(t); + stream.consume(); } } - + private void enqueue(Token t) { enqueueHiddens(t); tokens.addElement(t); @@ -276,7 +280,9 @@ private List enqueueHiddens(Token t) { } } } - List hiddenTokens = stream.getTokens(lastTokenAddedIndex + 1,t.getTokenIndex() - 1); + + List hiddenTokens = + stream.getTokens(lastTokenAddedIndex + 1, t.getTokenIndex() - 1); if (hiddenTokens != null) { tokens.addAll(hiddenTokens); } @@ -361,6 +367,7 @@ public String stackString() { return buf.toString(); } + @Override public String getSourceName() { return filename; } @@ -378,13 +385,13 @@ public String getSourceName() { a c b c -a c \n INDENT b \n DEDENT c \n EOF +a c \n INDENT b \n DEDENT c \n EOF ------- t3 ------- a b c d -a \n INDENT b \n INDENT c \n DEDENT DEDENT d \n EOF +a \n INDENT b \n INDENT c \n DEDENT DEDENT d \n EOF ------- t4 ------- a c @@ -396,12 +403,12 @@ public String getSourceName() { i j k -a \n INDENT c \n INDENT d \n DEDENT e \n f \n INDENT g \n h \n i \n INDENT j \n DEDENT DEDENT k \n DEDENT EOF +a \n INDENT c \n INDENT d \n DEDENT e \n f \n INDENT g \n h \n i \n INDENT j \n DEDENT DEDENT k \n DEDENT EOF ------- t5 ------- a b c d e -a \n INDENT b \n c \n INDENT d \n e \n DEDENT DEDENT EOF +a \n INDENT b \n c \n INDENT d \n e \n DEDENT DEDENT EOF */ diff --git a/src/org/python/antlr/PythonTree.java b/src/org/python/antlr/PythonTree.java index d1ffe0481..91a4e4d93 100644 --- a/src/org/python/antlr/PythonTree.java +++ b/src/org/python/antlr/PythonTree.java @@ -78,7 +78,7 @@ public String getText() { return node.getText(); } - public int getLine() { + protected int getLine() { if (node.getToken()==null || node.getToken().getLine()==0) { if ( getChildCount()>0 ) { return getChild(0).getLine(); @@ -88,7 +88,7 @@ public int getLine() { return node.getToken().getLine(); } - public int getCharPositionInLine() { + protected int getCharPositionInLine() { Token token = node.getToken(); if (token==null || token.getCharPositionInLine()==-1) { if (getChildCount()>0) { @@ -105,6 +105,14 @@ public int getCharPositionInLine() { return token.getCharPositionInLine(); } + public int getLineno() { + return getLine(); + } + + public int getCol_offset() { + return getCharPositionInLine(); + } + public int getTokenStartIndex() { return node.getTokenStartIndex(); } diff --git a/src/org/python/antlr/Visitor.java b/src/org/python/antlr/Visitor.java index 883a9741a..514308c62 100644 --- a/src/org/python/antlr/Visitor.java +++ b/src/org/python/antlr/Visitor.java @@ -6,8 +6,9 @@ public class Visitor extends VisitorBase { /** * Visit each of the children one by one. - * @args node The node whose children will be visited. + * @param node The node whose children will be visited. */ + @Override public void traverse(PythonTree node) throws Exception { node.traverse(this); } @@ -27,6 +28,7 @@ public Object visit(PythonTree node) throws Exception { return ret; } + @Override protected Object unhandled_node(PythonTree node) throws Exception { return this; } diff --git a/src/org/python/antlr/adapter/AstAdapter.java b/src/org/python/antlr/adapter/AstAdapter.java index 953a23a32..4386fa1d0 100644 --- a/src/org/python/antlr/adapter/AstAdapter.java +++ b/src/org/python/antlr/adapter/AstAdapter.java @@ -1,8 +1,8 @@ package org.python.antlr.adapter; import org.python.core.PyObject; - import java.util.List; + /** * AstAdapters turn Objects into Ast nodes. */ diff --git a/src/org/python/antlr/adapter/AstAdapters.java b/src/org/python/antlr/adapter/AstAdapters.java index 777c81682..43a9c4a01 100644 --- a/src/org/python/antlr/adapter/AstAdapters.java +++ b/src/org/python/antlr/adapter/AstAdapters.java @@ -5,10 +5,10 @@ import org.python.antlr.op.*; import org.python.core.*; -import java.util.ArrayList; /** * AstAdapter turns Python and Java objects into ast nodes. */ +@SuppressWarnings("unchecked") public class AstAdapters { public final static AliasAdapter aliasAdapter = new AliasAdapter(); public final static CmpopAdapter cmpopAdapter = new CmpopAdapter(); diff --git a/src/org/python/antlr/ast/Assert.java b/src/org/python/antlr/ast/Assert.java index c63f24a64..8d0f36a05 100644 --- a/src/org/python/antlr/ast/Assert.java +++ b/src/org/python/antlr/ast/Assert.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Assert", base = stmt.class) public class Assert extends stmt { diff --git a/src/org/python/antlr/ast/AssertDerived.java b/src/org/python/antlr/ast/AssertDerived.java index 8604b0b61..942e34f84 100644 --- a/src/org/python/antlr/ast/AssertDerived.java +++ b/src/org/python/antlr/ast/AssertDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Assign.java b/src/org/python/antlr/ast/Assign.java index ee8e8f3e7..a4ad15300 100644 --- a/src/org/python/antlr/ast/Assign.java +++ b/src/org/python/antlr/ast/Assign.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Assign", base = stmt.class) diff --git a/src/org/python/antlr/ast/AssignDerived.java b/src/org/python/antlr/ast/AssignDerived.java index e86942773..c73b38ce0 100644 --- a/src/org/python/antlr/ast/AssignDerived.java +++ b/src/org/python/antlr/ast/AssignDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/AstModule.java b/src/org/python/antlr/ast/AstModule.java index 44a9dad7a..0b4f484d0 100644 --- a/src/org/python/antlr/ast/AstModule.java +++ b/src/org/python/antlr/ast/AstModule.java @@ -5,15 +5,11 @@ import org.python.core.AstList; import org.python.core.ClassDictInit; import org.python.core.CompilerFlags; -import org.python.core.imp; import org.python.core.Py; import org.python.core.PyInteger; import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyType; - import org.python.antlr.AST; -import org.python.core.exceptions; public class AstModule implements ClassDictInit { diff --git a/src/org/python/antlr/ast/Attribute.java b/src/org/python/antlr/ast/Attribute.java index 7507aaee8..26143bfae 100644 --- a/src/org/python/antlr/ast/Attribute.java +++ b/src/org/python/antlr/ast/Attribute.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Attribute", base = expr.class) public class Attribute extends expr implements Context { diff --git a/src/org/python/antlr/ast/AttributeDerived.java b/src/org/python/antlr/ast/AttributeDerived.java index a97143fe6..aaa1722e4 100644 --- a/src/org/python/antlr/ast/AttributeDerived.java +++ b/src/org/python/antlr/ast/AttributeDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/AugAssign.java b/src/org/python/antlr/ast/AugAssign.java index a3f30a8b4..191cb944e 100644 --- a/src/org/python/antlr/ast/AugAssign.java +++ b/src/org/python/antlr/ast/AugAssign.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.AugAssign", base = stmt.class) public class AugAssign extends stmt { diff --git a/src/org/python/antlr/ast/AugAssignDerived.java b/src/org/python/antlr/ast/AugAssignDerived.java index 5845a9a44..eb7154f72 100644 --- a/src/org/python/antlr/ast/AugAssignDerived.java +++ b/src/org/python/antlr/ast/AugAssignDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/BinOp.java b/src/org/python/antlr/ast/BinOp.java index d33197532..133b9ee5c 100644 --- a/src/org/python/antlr/ast/BinOp.java +++ b/src/org/python/antlr/ast/BinOp.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.BinOp", base = expr.class) public class BinOp extends expr { diff --git a/src/org/python/antlr/ast/BinOpDerived.java b/src/org/python/antlr/ast/BinOpDerived.java index 52039710a..95aaadfdd 100644 --- a/src/org/python/antlr/ast/BinOpDerived.java +++ b/src/org/python/antlr/ast/BinOpDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/BoolOp.java b/src/org/python/antlr/ast/BoolOp.java index 5e381e214..8484955a3 100644 --- a/src/org/python/antlr/ast/BoolOp.java +++ b/src/org/python/antlr/ast/BoolOp.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.BoolOp", base = expr.class) diff --git a/src/org/python/antlr/ast/BoolOpDerived.java b/src/org/python/antlr/ast/BoolOpDerived.java index fd5b36397..ca7a5c1d9 100644 --- a/src/org/python/antlr/ast/BoolOpDerived.java +++ b/src/org/python/antlr/ast/BoolOpDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Break.java b/src/org/python/antlr/ast/Break.java index 9222cdbeb..77907588a 100644 --- a/src/org/python/antlr/ast/Break.java +++ b/src/org/python/antlr/ast/Break.java @@ -1,31 +1,19 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Break", base = stmt.class) public class Break extends stmt { diff --git a/src/org/python/antlr/ast/BreakDerived.java b/src/org/python/antlr/ast/BreakDerived.java index ba1e91fab..013db29ac 100644 --- a/src/org/python/antlr/ast/BreakDerived.java +++ b/src/org/python/antlr/ast/BreakDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Call.java b/src/org/python/antlr/ast/Call.java index c31b38c47..08c0f385f 100644 --- a/src/org/python/antlr/ast/Call.java +++ b/src/org/python/antlr/ast/Call.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Call", base = expr.class) diff --git a/src/org/python/antlr/ast/CallDerived.java b/src/org/python/antlr/ast/CallDerived.java index cd4a00de7..1d31d0906 100644 --- a/src/org/python/antlr/ast/CallDerived.java +++ b/src/org/python/antlr/ast/CallDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/ClassDef.java b/src/org/python/antlr/ast/ClassDef.java index d4aa26b65..e2abe56fe 100644 --- a/src/org/python/antlr/ast/ClassDef.java +++ b/src/org/python/antlr/ast/ClassDef.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.ClassDef", base = stmt.class) diff --git a/src/org/python/antlr/ast/ClassDefDerived.java b/src/org/python/antlr/ast/ClassDefDerived.java index 151b7c41e..fbe6351b1 100644 --- a/src/org/python/antlr/ast/ClassDefDerived.java +++ b/src/org/python/antlr/ast/ClassDefDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Compare.java b/src/org/python/antlr/ast/Compare.java index 56c931a07..698e4c64d 100644 --- a/src/org/python/antlr/ast/Compare.java +++ b/src/org/python/antlr/ast/Compare.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Compare", base = expr.class) diff --git a/src/org/python/antlr/ast/CompareDerived.java b/src/org/python/antlr/ast/CompareDerived.java index 192d83a0d..24f417f68 100644 --- a/src/org/python/antlr/ast/CompareDerived.java +++ b/src/org/python/antlr/ast/CompareDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Continue.java b/src/org/python/antlr/ast/Continue.java index dcc43e162..c3107548c 100644 --- a/src/org/python/antlr/ast/Continue.java +++ b/src/org/python/antlr/ast/Continue.java @@ -1,31 +1,19 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Continue", base = stmt.class) public class Continue extends stmt { diff --git a/src/org/python/antlr/ast/ContinueDerived.java b/src/org/python/antlr/ast/ContinueDerived.java index 72db75a77..5685c8ee0 100644 --- a/src/org/python/antlr/ast/ContinueDerived.java +++ b/src/org/python/antlr/ast/ContinueDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Delete.java b/src/org/python/antlr/ast/Delete.java index f7f09eb1a..2cac59088 100644 --- a/src/org/python/antlr/ast/Delete.java +++ b/src/org/python/antlr/ast/Delete.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Delete", base = stmt.class) diff --git a/src/org/python/antlr/ast/DeleteDerived.java b/src/org/python/antlr/ast/DeleteDerived.java index 40279372a..3a7ac27f9 100644 --- a/src/org/python/antlr/ast/DeleteDerived.java +++ b/src/org/python/antlr/ast/DeleteDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Dict.java b/src/org/python/antlr/ast/Dict.java index 721bf8ecb..c887ec691 100644 --- a/src/org/python/antlr/ast/Dict.java +++ b/src/org/python/antlr/ast/Dict.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Dict", base = expr.class) diff --git a/src/org/python/antlr/ast/DictComp.java b/src/org/python/antlr/ast/DictComp.java index 2a5c035b3..f07645222 100644 --- a/src/org/python/antlr/ast/DictComp.java +++ b/src/org/python/antlr/ast/DictComp.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.DictComp", base = expr.class) diff --git a/src/org/python/antlr/ast/DictDerived.java b/src/org/python/antlr/ast/DictDerived.java index 51b0e9df6..1f6dcf1c8 100644 --- a/src/org/python/antlr/ast/DictDerived.java +++ b/src/org/python/antlr/ast/DictDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Ellipsis.java b/src/org/python/antlr/ast/Ellipsis.java index 0224d901e..c07a5ba8f 100644 --- a/src/org/python/antlr/ast/Ellipsis.java +++ b/src/org/python/antlr/ast/Ellipsis.java @@ -1,31 +1,18 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Ellipsis", base = slice.class) public class Ellipsis extends slice { diff --git a/src/org/python/antlr/ast/EllipsisDerived.java b/src/org/python/antlr/ast/EllipsisDerived.java index 963a41225..c72886c21 100644 --- a/src/org/python/antlr/ast/EllipsisDerived.java +++ b/src/org/python/antlr/ast/EllipsisDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/ErrorSlice.java b/src/org/python/antlr/ast/ErrorSlice.java index f75c8e61f..741e991b4 100644 --- a/src/org/python/antlr/ast/ErrorSlice.java +++ b/src/org/python/antlr/ast/ErrorSlice.java @@ -1,10 +1,7 @@ package org.python.antlr.ast; + import org.python.antlr.PythonTree; import org.python.antlr.base.slice; -import org.antlr.runtime.CommonToken; -import org.antlr.runtime.Token; -import java.io.DataOutputStream; -import java.io.IOException; public class ErrorSlice extends slice { diff --git a/src/org/python/antlr/ast/ErrorStmt.java b/src/org/python/antlr/ast/ErrorStmt.java index ea8aa6801..7272b9fc5 100644 --- a/src/org/python/antlr/ast/ErrorStmt.java +++ b/src/org/python/antlr/ast/ErrorStmt.java @@ -1,10 +1,7 @@ package org.python.antlr.ast; + import org.python.antlr.PythonTree; import org.python.antlr.base.stmt; -import org.antlr.runtime.CommonToken; -import org.antlr.runtime.Token; -import java.io.DataOutputStream; -import java.io.IOException; public class ErrorStmt extends stmt { diff --git a/src/org/python/antlr/ast/ExceptHandler.java b/src/org/python/antlr/ast/ExceptHandler.java index 9bfad370f..c1d24c85b 100644 --- a/src/org/python/antlr/ast/ExceptHandler.java +++ b/src/org/python/antlr/ast/ExceptHandler.java @@ -1,14 +1,11 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +14,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.ExceptHandler", base = excepthandler.class) diff --git a/src/org/python/antlr/ast/ExceptHandlerDerived.java b/src/org/python/antlr/ast/ExceptHandlerDerived.java index a1cabdfef..4a7c82742 100644 --- a/src/org/python/antlr/ast/ExceptHandlerDerived.java +++ b/src/org/python/antlr/ast/ExceptHandlerDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Exec.java b/src/org/python/antlr/ast/Exec.java index 770d55f0b..23e54582e 100644 --- a/src/org/python/antlr/ast/Exec.java +++ b/src/org/python/antlr/ast/Exec.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Exec", base = stmt.class) public class Exec extends stmt { diff --git a/src/org/python/antlr/ast/ExecDerived.java b/src/org/python/antlr/ast/ExecDerived.java index de747cba2..da93f9223 100644 --- a/src/org/python/antlr/ast/ExecDerived.java +++ b/src/org/python/antlr/ast/ExecDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Expr.java b/src/org/python/antlr/ast/Expr.java index f1cef0765..3730a8b91 100644 --- a/src/org/python/antlr/ast/Expr.java +++ b/src/org/python/antlr/ast/Expr.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Expr", base = stmt.class) public class Expr extends stmt { diff --git a/src/org/python/antlr/ast/ExprDerived.java b/src/org/python/antlr/ast/ExprDerived.java index cb5d8d044..18de9f00e 100644 --- a/src/org/python/antlr/ast/ExprDerived.java +++ b/src/org/python/antlr/ast/ExprDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Expression.java b/src/org/python/antlr/ast/Expression.java index 773b7034d..7e0594d04 100644 --- a/src/org/python/antlr/ast/Expression.java +++ b/src/org/python/antlr/ast/Expression.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Expression", base = mod.class) public class Expression extends mod { diff --git a/src/org/python/antlr/ast/ExpressionDerived.java b/src/org/python/antlr/ast/ExpressionDerived.java index 9adbebc30..4d73d44cb 100644 --- a/src/org/python/antlr/ast/ExpressionDerived.java +++ b/src/org/python/antlr/ast/ExpressionDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/ExtSlice.java b/src/org/python/antlr/ast/ExtSlice.java index ed7993f78..6622cdcd2 100644 --- a/src/org/python/antlr/ast/ExtSlice.java +++ b/src/org/python/antlr/ast/ExtSlice.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.ExtSlice", base = slice.class) diff --git a/src/org/python/antlr/ast/ExtSliceDerived.java b/src/org/python/antlr/ast/ExtSliceDerived.java index d6d0a87a1..02933db05 100644 --- a/src/org/python/antlr/ast/ExtSliceDerived.java +++ b/src/org/python/antlr/ast/ExtSliceDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/For.java b/src/org/python/antlr/ast/For.java index 6a942b384..3cbaafb38 100644 --- a/src/org/python/antlr/ast/For.java +++ b/src/org/python/antlr/ast/For.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.For", base = stmt.class) diff --git a/src/org/python/antlr/ast/ForDerived.java b/src/org/python/antlr/ast/ForDerived.java index 31ff9d70a..e922d1021 100644 --- a/src/org/python/antlr/ast/ForDerived.java +++ b/src/org/python/antlr/ast/ForDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/FunctionDef.java b/src/org/python/antlr/ast/FunctionDef.java index 4cce67142..5a10cdc77 100644 --- a/src/org/python/antlr/ast/FunctionDef.java +++ b/src/org/python/antlr/ast/FunctionDef.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.FunctionDef", base = stmt.class) diff --git a/src/org/python/antlr/ast/FunctionDefDerived.java b/src/org/python/antlr/ast/FunctionDefDerived.java index 36a85b627..a2cbf5eeb 100644 --- a/src/org/python/antlr/ast/FunctionDefDerived.java +++ b/src/org/python/antlr/ast/FunctionDefDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/GeneratorExp.java b/src/org/python/antlr/ast/GeneratorExp.java index 160438e3a..c9b6c94ac 100644 --- a/src/org/python/antlr/ast/GeneratorExp.java +++ b/src/org/python/antlr/ast/GeneratorExp.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.GeneratorExp", base = expr.class) diff --git a/src/org/python/antlr/ast/GeneratorExpDerived.java b/src/org/python/antlr/ast/GeneratorExpDerived.java index ab5bb850f..8edc980a0 100644 --- a/src/org/python/antlr/ast/GeneratorExpDerived.java +++ b/src/org/python/antlr/ast/GeneratorExpDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Global.java b/src/org/python/antlr/ast/Global.java index 27f168ffe..0d84f0f15 100644 --- a/src/org/python/antlr/ast/Global.java +++ b/src/org/python/antlr/ast/Global.java @@ -1,14 +1,9 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,15 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Global", base = stmt.class) public class Global extends stmt { diff --git a/src/org/python/antlr/ast/GlobalDerived.java b/src/org/python/antlr/ast/GlobalDerived.java index f2eb0cd07..a44c2afa7 100644 --- a/src/org/python/antlr/ast/GlobalDerived.java +++ b/src/org/python/antlr/ast/GlobalDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/If.java b/src/org/python/antlr/ast/If.java index fc3e92fbc..ea316f888 100644 --- a/src/org/python/antlr/ast/If.java +++ b/src/org/python/antlr/ast/If.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.If", base = stmt.class) diff --git a/src/org/python/antlr/ast/IfDerived.java b/src/org/python/antlr/ast/IfDerived.java index ad092768c..135fc1989 100644 --- a/src/org/python/antlr/ast/IfDerived.java +++ b/src/org/python/antlr/ast/IfDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/IfExp.java b/src/org/python/antlr/ast/IfExp.java index 0af807cfe..65ab4bbda 100644 --- a/src/org/python/antlr/ast/IfExp.java +++ b/src/org/python/antlr/ast/IfExp.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.IfExp", base = expr.class) public class IfExp extends expr { diff --git a/src/org/python/antlr/ast/IfExpDerived.java b/src/org/python/antlr/ast/IfExpDerived.java index e24982a6c..b55acebce 100644 --- a/src/org/python/antlr/ast/IfExpDerived.java +++ b/src/org/python/antlr/ast/IfExpDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Import.java b/src/org/python/antlr/ast/Import.java index bc37ddc44..6305f3199 100644 --- a/src/org/python/antlr/ast/Import.java +++ b/src/org/python/antlr/ast/Import.java @@ -1,14 +1,9 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Import", base = stmt.class) diff --git a/src/org/python/antlr/ast/ImportDerived.java b/src/org/python/antlr/ast/ImportDerived.java index 9ed1c7292..0256456a1 100644 --- a/src/org/python/antlr/ast/ImportDerived.java +++ b/src/org/python/antlr/ast/ImportDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/ImportFrom.java b/src/org/python/antlr/ast/ImportFrom.java index 643124668..b5fd4d741 100644 --- a/src/org/python/antlr/ast/ImportFrom.java +++ b/src/org/python/antlr/ast/ImportFrom.java @@ -1,14 +1,9 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.ImportFrom", base = stmt.class) diff --git a/src/org/python/antlr/ast/ImportFromDerived.java b/src/org/python/antlr/ast/ImportFromDerived.java index 89843e8d3..614d0fad8 100644 --- a/src/org/python/antlr/ast/ImportFromDerived.java +++ b/src/org/python/antlr/ast/ImportFromDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Index.java b/src/org/python/antlr/ast/Index.java index 5d0d70fe6..49cf6bc57 100644 --- a/src/org/python/antlr/ast/Index.java +++ b/src/org/python/antlr/ast/Index.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Index", base = slice.class) public class Index extends slice { diff --git a/src/org/python/antlr/ast/IndexDerived.java b/src/org/python/antlr/ast/IndexDerived.java index 1cf4d7001..cfbe31577 100644 --- a/src/org/python/antlr/ast/IndexDerived.java +++ b/src/org/python/antlr/ast/IndexDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Interactive.java b/src/org/python/antlr/ast/Interactive.java index 7267bde05..5e597a705 100644 --- a/src/org/python/antlr/ast/Interactive.java +++ b/src/org/python/antlr/ast/Interactive.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Interactive", base = mod.class) diff --git a/src/org/python/antlr/ast/InteractiveDerived.java b/src/org/python/antlr/ast/InteractiveDerived.java index fcb752ad5..7c38d7f16 100644 --- a/src/org/python/antlr/ast/InteractiveDerived.java +++ b/src/org/python/antlr/ast/InteractiveDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Lambda.java b/src/org/python/antlr/ast/Lambda.java index 621a3e260..fab929c7e 100644 --- a/src/org/python/antlr/ast/Lambda.java +++ b/src/org/python/antlr/ast/Lambda.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Lambda", base = expr.class) public class Lambda extends expr { diff --git a/src/org/python/antlr/ast/LambdaDerived.java b/src/org/python/antlr/ast/LambdaDerived.java index e3fc55b8c..1ab9cf9d0 100644 --- a/src/org/python/antlr/ast/LambdaDerived.java +++ b/src/org/python/antlr/ast/LambdaDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/List.java b/src/org/python/antlr/ast/List.java index 4d3c03889..9d45f2037 100644 --- a/src/org/python/antlr/ast/List.java +++ b/src/org/python/antlr/ast/List.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.List", base = expr.class) diff --git a/src/org/python/antlr/ast/ListComp.java b/src/org/python/antlr/ast/ListComp.java index 9c2852ab7..b3f467495 100644 --- a/src/org/python/antlr/ast/ListComp.java +++ b/src/org/python/antlr/ast/ListComp.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.ListComp", base = expr.class) diff --git a/src/org/python/antlr/ast/ListCompDerived.java b/src/org/python/antlr/ast/ListCompDerived.java index 8628bedb1..1280c30e3 100644 --- a/src/org/python/antlr/ast/ListCompDerived.java +++ b/src/org/python/antlr/ast/ListCompDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/ListDerived.java b/src/org/python/antlr/ast/ListDerived.java index 26545b5eb..519b26f94 100644 --- a/src/org/python/antlr/ast/ListDerived.java +++ b/src/org/python/antlr/ast/ListDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Module.java b/src/org/python/antlr/ast/Module.java index c2abfff38..ad07655f8 100644 --- a/src/org/python/antlr/ast/Module.java +++ b/src/org/python/antlr/ast/Module.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Module", base = mod.class) diff --git a/src/org/python/antlr/ast/ModuleDerived.java b/src/org/python/antlr/ast/ModuleDerived.java index c774a3755..3278637db 100644 --- a/src/org/python/antlr/ast/ModuleDerived.java +++ b/src/org/python/antlr/ast/ModuleDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Name.java b/src/org/python/antlr/ast/Name.java index 7c40aa761..2161abf7d 100644 --- a/src/org/python/antlr/ast/Name.java +++ b/src/org/python/antlr/ast/Name.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Name", base = expr.class) public class Name extends expr implements Context { diff --git a/src/org/python/antlr/ast/NameDerived.java b/src/org/python/antlr/ast/NameDerived.java index e938b86c4..ba118423e 100644 --- a/src/org/python/antlr/ast/NameDerived.java +++ b/src/org/python/antlr/ast/NameDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Num.java b/src/org/python/antlr/ast/Num.java index aa158c64d..755f2e524 100644 --- a/src/org/python/antlr/ast/Num.java +++ b/src/org/python/antlr/ast/Num.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Num", base = expr.class) public class Num extends expr { diff --git a/src/org/python/antlr/ast/NumDerived.java b/src/org/python/antlr/ast/NumDerived.java index 8a45dbd3a..3be1728ef 100644 --- a/src/org/python/antlr/ast/NumDerived.java +++ b/src/org/python/antlr/ast/NumDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Pass.java b/src/org/python/antlr/ast/Pass.java index c87bed094..b815c1ae3 100644 --- a/src/org/python/antlr/ast/Pass.java +++ b/src/org/python/antlr/ast/Pass.java @@ -1,31 +1,19 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Pass", base = stmt.class) public class Pass extends stmt { diff --git a/src/org/python/antlr/ast/PassDerived.java b/src/org/python/antlr/ast/PassDerived.java index 15502248d..cff553e8f 100644 --- a/src/org/python/antlr/ast/PassDerived.java +++ b/src/org/python/antlr/ast/PassDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Print.java b/src/org/python/antlr/ast/Print.java index c1968d99c..704950073 100644 --- a/src/org/python/antlr/ast/Print.java +++ b/src/org/python/antlr/ast/Print.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Print", base = stmt.class) diff --git a/src/org/python/antlr/ast/PrintDerived.java b/src/org/python/antlr/ast/PrintDerived.java index 094ec95be..bc4252431 100644 --- a/src/org/python/antlr/ast/PrintDerived.java +++ b/src/org/python/antlr/ast/PrintDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Raise.java b/src/org/python/antlr/ast/Raise.java index 2d294d608..a6d5a3783 100644 --- a/src/org/python/antlr/ast/Raise.java +++ b/src/org/python/antlr/ast/Raise.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Raise", base = stmt.class) public class Raise extends stmt { diff --git a/src/org/python/antlr/ast/RaiseDerived.java b/src/org/python/antlr/ast/RaiseDerived.java index 5719f9adc..d6c199b8d 100644 --- a/src/org/python/antlr/ast/RaiseDerived.java +++ b/src/org/python/antlr/ast/RaiseDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Repr.java b/src/org/python/antlr/ast/Repr.java index d1e11d37b..4b7d84202 100644 --- a/src/org/python/antlr/ast/Repr.java +++ b/src/org/python/antlr/ast/Repr.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Repr", base = expr.class) public class Repr extends expr { diff --git a/src/org/python/antlr/ast/ReprDerived.java b/src/org/python/antlr/ast/ReprDerived.java index f4a06d5fa..5e33e861a 100644 --- a/src/org/python/antlr/ast/ReprDerived.java +++ b/src/org/python/antlr/ast/ReprDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Return.java b/src/org/python/antlr/ast/Return.java index 877a44555..16a6c509b 100644 --- a/src/org/python/antlr/ast/Return.java +++ b/src/org/python/antlr/ast/Return.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Return", base = stmt.class) public class Return extends stmt { diff --git a/src/org/python/antlr/ast/ReturnDerived.java b/src/org/python/antlr/ast/ReturnDerived.java index 1b27ab0c5..69f18c7fb 100644 --- a/src/org/python/antlr/ast/ReturnDerived.java +++ b/src/org/python/antlr/ast/ReturnDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Set.java b/src/org/python/antlr/ast/Set.java index c52793255..dd4caf5df 100644 --- a/src/org/python/antlr/ast/Set.java +++ b/src/org/python/antlr/ast/Set.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Set", base = expr.class) diff --git a/src/org/python/antlr/ast/SetComp.java b/src/org/python/antlr/ast/SetComp.java index 11a742e95..8714c5806 100644 --- a/src/org/python/antlr/ast/SetComp.java +++ b/src/org/python/antlr/ast/SetComp.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.SetComp", base = expr.class) diff --git a/src/org/python/antlr/ast/SetCompDerived.java b/src/org/python/antlr/ast/SetCompDerived.java new file mode 100644 index 000000000..b9db7c4c8 --- /dev/null +++ b/src/org/python/antlr/ast/SetCompDerived.java @@ -0,0 +1,1175 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.antlr.ast; + +import java.io.Serializable; +import org.python.core.*; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class SetCompDerived extends SetComp implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + + public String toString() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__repr__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (!(res instanceof PyString)) + throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")"); + return((PyString)res).toString(); + } + return super.toString(); + } + +} diff --git a/src/org/python/antlr/ast/SetDerived.java b/src/org/python/antlr/ast/SetDerived.java new file mode 100644 index 000000000..ece756874 --- /dev/null +++ b/src/org/python/antlr/ast/SetDerived.java @@ -0,0 +1,1175 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.antlr.ast; + +import java.io.Serializable; +import org.python.core.*; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class SetDerived extends Set implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + + public String toString() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__repr__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (!(res instanceof PyString)) + throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")"); + return((PyString)res).toString(); + } + return super.toString(); + } + +} diff --git a/src/org/python/antlr/ast/Slice.java b/src/org/python/antlr/ast/Slice.java index 0a8c91a69..cfddb86b3 100644 --- a/src/org/python/antlr/ast/Slice.java +++ b/src/org/python/antlr/ast/Slice.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Slice", base = slice.class) public class Slice extends slice { diff --git a/src/org/python/antlr/ast/SliceDerived.java b/src/org/python/antlr/ast/SliceDerived.java index 1b2eae7e8..ab9b8cbe0 100644 --- a/src/org/python/antlr/ast/SliceDerived.java +++ b/src/org/python/antlr/ast/SliceDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Str.java b/src/org/python/antlr/ast/Str.java index 0e3827ae6..f86097f15 100644 --- a/src/org/python/antlr/ast/Str.java +++ b/src/org/python/antlr/ast/Str.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Str", base = expr.class) public class Str extends expr { diff --git a/src/org/python/antlr/ast/StrDerived.java b/src/org/python/antlr/ast/StrDerived.java index ff6d917ca..1316692e5 100644 --- a/src/org/python/antlr/ast/StrDerived.java +++ b/src/org/python/antlr/ast/StrDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Subscript.java b/src/org/python/antlr/ast/Subscript.java index 5af2f9c81..3c82acbfa 100644 --- a/src/org/python/antlr/ast/Subscript.java +++ b/src/org/python/antlr/ast/Subscript.java @@ -1,31 +1,22 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Subscript", base = expr.class) public class Subscript extends expr implements Context { diff --git a/src/org/python/antlr/ast/SubscriptDerived.java b/src/org/python/antlr/ast/SubscriptDerived.java index d641d196e..91e441c45 100644 --- a/src/org/python/antlr/ast/SubscriptDerived.java +++ b/src/org/python/antlr/ast/SubscriptDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Suite.java b/src/org/python/antlr/ast/Suite.java index d6439dc1c..cb179a12a 100644 --- a/src/org/python/antlr/ast/Suite.java +++ b/src/org/python/antlr/ast/Suite.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Suite", base = mod.class) diff --git a/src/org/python/antlr/ast/SuiteDerived.java b/src/org/python/antlr/ast/SuiteDerived.java index 779081a76..6b28a9cd5 100644 --- a/src/org/python/antlr/ast/SuiteDerived.java +++ b/src/org/python/antlr/ast/SuiteDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/TryExcept.java b/src/org/python/antlr/ast/TryExcept.java index b9b543f38..f5fd46880 100644 --- a/src/org/python/antlr/ast/TryExcept.java +++ b/src/org/python/antlr/ast/TryExcept.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.TryExcept", base = stmt.class) diff --git a/src/org/python/antlr/ast/TryExceptDerived.java b/src/org/python/antlr/ast/TryExceptDerived.java index 7ff44182d..550936da5 100644 --- a/src/org/python/antlr/ast/TryExceptDerived.java +++ b/src/org/python/antlr/ast/TryExceptDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/TryFinally.java b/src/org/python/antlr/ast/TryFinally.java index 55f94ff5c..cf3844b19 100644 --- a/src/org/python/antlr/ast/TryFinally.java +++ b/src/org/python/antlr/ast/TryFinally.java @@ -1,14 +1,9 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.TryFinally", base = stmt.class) diff --git a/src/org/python/antlr/ast/TryFinallyDerived.java b/src/org/python/antlr/ast/TryFinallyDerived.java index 69d5c832c..7a9cc90f7 100644 --- a/src/org/python/antlr/ast/TryFinallyDerived.java +++ b/src/org/python/antlr/ast/TryFinallyDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Tuple.java b/src/org/python/antlr/ast/Tuple.java index ea6acf91c..b171dd0e9 100644 --- a/src/org/python/antlr/ast/Tuple.java +++ b/src/org/python/antlr/ast/Tuple.java @@ -1,15 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -17,14 +12,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.Tuple", base = expr.class) diff --git a/src/org/python/antlr/ast/TupleDerived.java b/src/org/python/antlr/ast/TupleDerived.java index e0a22f437..43c7d6c4b 100644 --- a/src/org/python/antlr/ast/TupleDerived.java +++ b/src/org/python/antlr/ast/TupleDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/UnaryOp.java b/src/org/python/antlr/ast/UnaryOp.java index 47b032821..d858f211d 100644 --- a/src/org/python/antlr/ast/UnaryOp.java +++ b/src/org/python/antlr/ast/UnaryOp.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.UnaryOp", base = expr.class) public class UnaryOp extends expr { diff --git a/src/org/python/antlr/ast/UnaryOpDerived.java b/src/org/python/antlr/ast/UnaryOpDerived.java index 12b391b72..0daa9b5ff 100644 --- a/src/org/python/antlr/ast/UnaryOpDerived.java +++ b/src/org/python/antlr/ast/UnaryOpDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/VisitorBase.java b/src/org/python/antlr/ast/VisitorBase.java index 33e630b7d..b6f153f42 100644 --- a/src/org/python/antlr/ast/VisitorBase.java +++ b/src/org/python/antlr/ast/VisitorBase.java @@ -1,28 +1,7 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; -import org.antlr.runtime.Token; -import org.python.antlr.AST; + import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; -import org.python.core.PyString; -import org.python.core.PyStringMap; -import org.python.core.PyType; -import org.python.core.Visitproc; -import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; -import org.python.expose.ExposedType; public abstract class VisitorBase implements VisitorIF { public R visitModule(Module node) throws Exception { diff --git a/src/org/python/antlr/ast/While.java b/src/org/python/antlr/ast/While.java index b9af351ae..5e5cf99ac 100644 --- a/src/org/python/antlr/ast/While.java +++ b/src/org/python/antlr/ast/While.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.While", base = stmt.class) diff --git a/src/org/python/antlr/ast/WhileDerived.java b/src/org/python/antlr/ast/WhileDerived.java index 01a7f9d86..492339c16 100644 --- a/src/org/python/antlr/ast/WhileDerived.java +++ b/src/org/python/antlr/ast/WhileDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/With.java b/src/org/python/antlr/ast/With.java index 79c70c42b..4cdf5cf26 100644 --- a/src/org/python/antlr/ast/With.java +++ b/src/org/python/antlr/ast/With.java @@ -1,14 +1,10 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; @@ -17,14 +13,11 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.With", base = stmt.class) diff --git a/src/org/python/antlr/ast/WithDerived.java b/src/org/python/antlr/ast/WithDerived.java index dc1313561..911abfe33 100644 --- a/src/org/python/antlr/ast/WithDerived.java +++ b/src/org/python/antlr/ast/WithDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/Yield.java b/src/org/python/antlr/ast/Yield.java index ad3ba4d37..06ec79fe6 100644 --- a/src/org/python/antlr/ast/Yield.java +++ b/src/org/python/antlr/ast/Yield.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; -import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.Yield", base = expr.class) public class Yield extends expr { diff --git a/src/org/python/antlr/ast/YieldDerived.java b/src/org/python/antlr/ast/YieldDerived.java index bf5464af6..fa511cb4e 100644 --- a/src/org/python/antlr/ast/YieldDerived.java +++ b/src/org/python/antlr/ast/YieldDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/alias.java b/src/org/python/antlr/ast/alias.java index 971279851..798066615 100644 --- a/src/org/python/antlr/ast/alias.java +++ b/src/org/python/antlr/ast/alias.java @@ -1,31 +1,21 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.alias", base = AST.class) public class alias extends PythonTree { diff --git a/src/org/python/antlr/ast/aliasDerived.java b/src/org/python/antlr/ast/aliasDerived.java index 6acf1d8f2..85fb1686c 100644 --- a/src/org/python/antlr/ast/aliasDerived.java +++ b/src/org/python/antlr/ast/aliasDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/arguments.java b/src/org/python/antlr/ast/arguments.java index ff81ff94d..7d0e2b803 100644 --- a/src/org/python/antlr/ast/arguments.java +++ b/src/org/python/antlr/ast/arguments.java @@ -1,15 +1,11 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -23,8 +19,6 @@ import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.arguments", base = AST.class) diff --git a/src/org/python/antlr/ast/argumentsDerived.java b/src/org/python/antlr/ast/argumentsDerived.java index 633af95b5..dcf05cef7 100644 --- a/src/org/python/antlr/ast/argumentsDerived.java +++ b/src/org/python/antlr/ast/argumentsDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/boolopType.java b/src/org/python/antlr/ast/boolopType.java index cc3b9243a..f023eeda4 100644 --- a/src/org/python/antlr/ast/boolopType.java +++ b/src/org/python/antlr/ast/boolopType.java @@ -1,8 +1,6 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.python.antlr.AST; - public enum boolopType { UNDEFINED, And, diff --git a/src/org/python/antlr/ast/cmpopType.java b/src/org/python/antlr/ast/cmpopType.java index b55182636..99bb9daf8 100644 --- a/src/org/python/antlr/ast/cmpopType.java +++ b/src/org/python/antlr/ast/cmpopType.java @@ -1,8 +1,6 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.python.antlr.AST; - public enum cmpopType { UNDEFINED, Eq, diff --git a/src/org/python/antlr/ast/comprehension.java b/src/org/python/antlr/ast/comprehension.java index c3905e4a6..8cb4bbd78 100644 --- a/src/org/python/antlr/ast/comprehension.java +++ b/src/org/python/antlr/ast/comprehension.java @@ -1,15 +1,11 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; import org.python.core.AstList; import org.python.core.Py; @@ -23,8 +19,6 @@ import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.ArrayList; @ExposedType(name = "_ast.comprehension", base = AST.class) diff --git a/src/org/python/antlr/ast/comprehensionDerived.java b/src/org/python/antlr/ast/comprehensionDerived.java index a4683ebfa..7517b88c0 100644 --- a/src/org/python/antlr/ast/comprehensionDerived.java +++ b/src/org/python/antlr/ast/comprehensionDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/expr_contextType.java b/src/org/python/antlr/ast/expr_contextType.java index ba32b7e5c..c6eb68225 100644 --- a/src/org/python/antlr/ast/expr_contextType.java +++ b/src/org/python/antlr/ast/expr_contextType.java @@ -1,8 +1,6 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.python.antlr.AST; - public enum expr_contextType { UNDEFINED, Load, diff --git a/src/org/python/antlr/ast/keyword.java b/src/org/python/antlr/ast/keyword.java index b268ffd8f..629191059 100644 --- a/src/org/python/antlr/ast/keyword.java +++ b/src/org/python/antlr/ast/keyword.java @@ -1,17 +1,12 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; import org.python.core.ArgParser; -import org.python.core.AstList; import org.python.core.Py; import org.python.core.PyObject; import org.python.core.PyString; @@ -23,9 +18,6 @@ import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; @ExposedType(name = "_ast.keyword", base = AST.class) public class keyword extends PythonTree { diff --git a/src/org/python/antlr/ast/keywordDerived.java b/src/org/python/antlr/ast/keywordDerived.java index e4a910740..022fa84a8 100644 --- a/src/org/python/antlr/ast/keywordDerived.java +++ b/src/org/python/antlr/ast/keywordDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/ast/operatorType.java b/src/org/python/antlr/ast/operatorType.java index f67c3db56..7050ec5e7 100644 --- a/src/org/python/antlr/ast/operatorType.java +++ b/src/org/python/antlr/ast/operatorType.java @@ -1,8 +1,6 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.python.antlr.AST; - public enum operatorType { UNDEFINED, Add, diff --git a/src/org/python/antlr/ast/unaryopType.java b/src/org/python/antlr/ast/unaryopType.java index 438d867f6..50c931924 100644 --- a/src/org/python/antlr/ast/unaryopType.java +++ b/src/org/python/antlr/ast/unaryopType.java @@ -1,8 +1,6 @@ // Autogenerated AST node package org.python.antlr.ast; -import org.python.antlr.AST; - public enum unaryopType { UNDEFINED, Invert, diff --git a/src/org/python/antlr/base/boolop.java b/src/org/python/antlr/base/boolop.java index 84b380506..7fddec05f 100644 --- a/src/org/python/antlr/base/boolop.java +++ b/src/org/python/antlr/base/boolop.java @@ -1,27 +1,13 @@ // Hand copied from stmt. // XXX: autogenerate this. package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.boolop", base = AST.class) diff --git a/src/org/python/antlr/base/cmpop.java b/src/org/python/antlr/base/cmpop.java index 4fabe846b..95d05a314 100644 --- a/src/org/python/antlr/base/cmpop.java +++ b/src/org/python/antlr/base/cmpop.java @@ -1,27 +1,13 @@ // Hand copied from stmt. // XXX: autogenerate this. package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.cmpop", base = AST.class) diff --git a/src/org/python/antlr/base/excepthandler.java b/src/org/python/antlr/base/excepthandler.java index 4f4e5680b..5b8417d4d 100644 --- a/src/org/python/antlr/base/excepthandler.java +++ b/src/org/python/antlr/base/excepthandler.java @@ -1,27 +1,13 @@ // Autogenerated AST node package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.excepthandler", base = AST.class) diff --git a/src/org/python/antlr/base/expr.java b/src/org/python/antlr/base/expr.java index b447975e8..ce4e1e412 100644 --- a/src/org/python/antlr/base/expr.java +++ b/src/org/python/antlr/base/expr.java @@ -1,27 +1,13 @@ // Autogenerated AST node package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.expr", base = AST.class) diff --git a/src/org/python/antlr/base/expr_context.java b/src/org/python/antlr/base/expr_context.java index 0aeebcc1d..90987b37e 100644 --- a/src/org/python/antlr/base/expr_context.java +++ b/src/org/python/antlr/base/expr_context.java @@ -1,27 +1,13 @@ // Hand copied from stmt. // XXX: autogenerate this. package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.expr_context", base = AST.class) diff --git a/src/org/python/antlr/base/mod.java b/src/org/python/antlr/base/mod.java index 1444a83e6..8ded40e1a 100644 --- a/src/org/python/antlr/base/mod.java +++ b/src/org/python/antlr/base/mod.java @@ -1,27 +1,13 @@ // Autogenerated AST node package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.mod", base = AST.class) diff --git a/src/org/python/antlr/base/operator.java b/src/org/python/antlr/base/operator.java index 594fc063a..7c7176357 100644 --- a/src/org/python/antlr/base/operator.java +++ b/src/org/python/antlr/base/operator.java @@ -1,27 +1,13 @@ // Hand copied from stmt. // XXX: autogenerate this. package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.operator", base = AST.class) diff --git a/src/org/python/antlr/base/slice.java b/src/org/python/antlr/base/slice.java index 8173306c9..14797cfbe 100644 --- a/src/org/python/antlr/base/slice.java +++ b/src/org/python/antlr/base/slice.java @@ -1,27 +1,13 @@ // Autogenerated AST node package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.slice", base = AST.class) diff --git a/src/org/python/antlr/base/stmt.java b/src/org/python/antlr/base/stmt.java index 2d72c90d4..ab9334d84 100644 --- a/src/org/python/antlr/base/stmt.java +++ b/src/org/python/antlr/base/stmt.java @@ -1,27 +1,13 @@ // Autogenerated AST node package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; -import org.python.core.Visitproc; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.stmt", base = AST.class) diff --git a/src/org/python/antlr/base/unaryop.java b/src/org/python/antlr/base/unaryop.java index 6c9c16fcd..0b0d6a457 100644 --- a/src/org/python/antlr/base/unaryop.java +++ b/src/org/python/antlr/base/unaryop.java @@ -1,27 +1,13 @@ // Hand copied from stmt. // XXX: autogenerate this. package org.python.antlr.base; -import org.antlr.runtime.CommonToken; + import org.antlr.runtime.Token; import org.python.antlr.AST; import org.python.antlr.PythonTree; -import org.python.antlr.adapter.AstAdapters; -import org.python.antlr.base.excepthandler; -import org.python.antlr.base.expr; -import org.python.antlr.base.mod; -import org.python.antlr.base.slice; -import org.python.antlr.base.stmt; -import org.python.core.ArgParser; -import org.python.core.AstList; -import org.python.core.Py; -import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PyType; import org.python.expose.ExposedGet; -import org.python.expose.ExposedMethod; -import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.unaryop", base = AST.class) diff --git a/src/org/python/antlr/op/Add.java b/src/org/python/antlr/op/Add.java index 1bb5519a8..bfa0149ed 100644 --- a/src/org/python/antlr/op/Add.java +++ b/src/org/python/antlr/op/Add.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Add", base = operator.class) diff --git a/src/org/python/antlr/op/AddDerived.java b/src/org/python/antlr/op/AddDerived.java index bdfe1d029..3499a7512 100644 --- a/src/org/python/antlr/op/AddDerived.java +++ b/src/org/python/antlr/op/AddDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/And.java b/src/org/python/antlr/op/And.java index cbffa5882..d7c7d134b 100644 --- a/src/org/python/antlr/op/And.java +++ b/src/org/python/antlr/op/And.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.boolop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.And", base = boolop.class) diff --git a/src/org/python/antlr/op/AndDerived.java b/src/org/python/antlr/op/AndDerived.java index 607ae5e61..a051c604b 100644 --- a/src/org/python/antlr/op/AndDerived.java +++ b/src/org/python/antlr/op/AndDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/AugLoad.java b/src/org/python/antlr/op/AugLoad.java index 0ad3c95e1..883e6defe 100644 --- a/src/org/python/antlr/op/AugLoad.java +++ b/src/org/python/antlr/op/AugLoad.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.AugLoad", base = expr_context.class) diff --git a/src/org/python/antlr/op/AugLoadDerived.java b/src/org/python/antlr/op/AugLoadDerived.java index 5538cba63..3d07863c7 100644 --- a/src/org/python/antlr/op/AugLoadDerived.java +++ b/src/org/python/antlr/op/AugLoadDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/AugStore.java b/src/org/python/antlr/op/AugStore.java index d50cd5bc6..dff0d9f53 100644 --- a/src/org/python/antlr/op/AugStore.java +++ b/src/org/python/antlr/op/AugStore.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.AugStore", base = expr_context.class) diff --git a/src/org/python/antlr/op/AugStoreDerived.java b/src/org/python/antlr/op/AugStoreDerived.java index efd87aee4..3221a35ee 100644 --- a/src/org/python/antlr/op/AugStoreDerived.java +++ b/src/org/python/antlr/op/AugStoreDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/BitAnd.java b/src/org/python/antlr/op/BitAnd.java index 3598ae58b..8435e9e7c 100644 --- a/src/org/python/antlr/op/BitAnd.java +++ b/src/org/python/antlr/op/BitAnd.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.BitAnd", base = operator.class) diff --git a/src/org/python/antlr/op/BitAndDerived.java b/src/org/python/antlr/op/BitAndDerived.java index d1b8712c1..dbfc42d3d 100644 --- a/src/org/python/antlr/op/BitAndDerived.java +++ b/src/org/python/antlr/op/BitAndDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/BitOr.java b/src/org/python/antlr/op/BitOr.java index 7aef05510..9685d6db8 100644 --- a/src/org/python/antlr/op/BitOr.java +++ b/src/org/python/antlr/op/BitOr.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.BitOr", base = operator.class) diff --git a/src/org/python/antlr/op/BitOrDerived.java b/src/org/python/antlr/op/BitOrDerived.java index 35060cb88..b37d92807 100644 --- a/src/org/python/antlr/op/BitOrDerived.java +++ b/src/org/python/antlr/op/BitOrDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/BitXor.java b/src/org/python/antlr/op/BitXor.java index 4c450996a..9465780dc 100644 --- a/src/org/python/antlr/op/BitXor.java +++ b/src/org/python/antlr/op/BitXor.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.BitXor", base = operator.class) diff --git a/src/org/python/antlr/op/BitXorDerived.java b/src/org/python/antlr/op/BitXorDerived.java index ce7b5bacb..92be665b7 100644 --- a/src/org/python/antlr/op/BitXorDerived.java +++ b/src/org/python/antlr/op/BitXorDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Del.java b/src/org/python/antlr/op/Del.java index ad472e5f8..635b37e24 100644 --- a/src/org/python/antlr/op/Del.java +++ b/src/org/python/antlr/op/Del.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Del", base = expr_context.class) diff --git a/src/org/python/antlr/op/DelDerived.java b/src/org/python/antlr/op/DelDerived.java index b462f40b6..26967198e 100644 --- a/src/org/python/antlr/op/DelDerived.java +++ b/src/org/python/antlr/op/DelDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Div.java b/src/org/python/antlr/op/Div.java index 8c6cfde29..1af0dd8fa 100644 --- a/src/org/python/antlr/op/Div.java +++ b/src/org/python/antlr/op/Div.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Div", base = operator.class) diff --git a/src/org/python/antlr/op/DivDerived.java b/src/org/python/antlr/op/DivDerived.java index 92f4ab482..bf1608153 100644 --- a/src/org/python/antlr/op/DivDerived.java +++ b/src/org/python/antlr/op/DivDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Eq.java b/src/org/python/antlr/op/Eq.java index 2c2330589..6236ad40a 100644 --- a/src/org/python/antlr/op/Eq.java +++ b/src/org/python/antlr/op/Eq.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Eq", base = cmpop.class) diff --git a/src/org/python/antlr/op/EqDerived.java b/src/org/python/antlr/op/EqDerived.java index ee3d2439f..82fa531e4 100644 --- a/src/org/python/antlr/op/EqDerived.java +++ b/src/org/python/antlr/op/EqDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/FloorDiv.java b/src/org/python/antlr/op/FloorDiv.java index 65f3b61e0..f252bd8bf 100644 --- a/src/org/python/antlr/op/FloorDiv.java +++ b/src/org/python/antlr/op/FloorDiv.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.FloorDiv", base = operator.class) diff --git a/src/org/python/antlr/op/FloorDivDerived.java b/src/org/python/antlr/op/FloorDivDerived.java index c2d9eb673..971a3289e 100644 --- a/src/org/python/antlr/op/FloorDivDerived.java +++ b/src/org/python/antlr/op/FloorDivDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Gt.java b/src/org/python/antlr/op/Gt.java index 81b850247..1e95c2b81 100644 --- a/src/org/python/antlr/op/Gt.java +++ b/src/org/python/antlr/op/Gt.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Gt", base = cmpop.class) diff --git a/src/org/python/antlr/op/GtDerived.java b/src/org/python/antlr/op/GtDerived.java index e5a9df3f7..53e724b80 100644 --- a/src/org/python/antlr/op/GtDerived.java +++ b/src/org/python/antlr/op/GtDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/GtE.java b/src/org/python/antlr/op/GtE.java index d1a5e694d..6680ecdc1 100644 --- a/src/org/python/antlr/op/GtE.java +++ b/src/org/python/antlr/op/GtE.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.GtE", base = cmpop.class) diff --git a/src/org/python/antlr/op/GtEDerived.java b/src/org/python/antlr/op/GtEDerived.java index 6353d290a..9244999d2 100644 --- a/src/org/python/antlr/op/GtEDerived.java +++ b/src/org/python/antlr/op/GtEDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/In.java b/src/org/python/antlr/op/In.java index 781e57cab..4306f47a5 100644 --- a/src/org/python/antlr/op/In.java +++ b/src/org/python/antlr/op/In.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.In", base = cmpop.class) diff --git a/src/org/python/antlr/op/InDerived.java b/src/org/python/antlr/op/InDerived.java index 5d14c05cb..8ed672126 100644 --- a/src/org/python/antlr/op/InDerived.java +++ b/src/org/python/antlr/op/InDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Invert.java b/src/org/python/antlr/op/Invert.java index c49f00a26..17bef292a 100644 --- a/src/org/python/antlr/op/Invert.java +++ b/src/org/python/antlr/op/Invert.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.unaryop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Invert", base = unaryop.class) diff --git a/src/org/python/antlr/op/InvertDerived.java b/src/org/python/antlr/op/InvertDerived.java index 422012dbc..247646333 100644 --- a/src/org/python/antlr/op/InvertDerived.java +++ b/src/org/python/antlr/op/InvertDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Is.java b/src/org/python/antlr/op/Is.java index 939a9591d..e8dc409c9 100644 --- a/src/org/python/antlr/op/Is.java +++ b/src/org/python/antlr/op/Is.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Is", base = cmpop.class) diff --git a/src/org/python/antlr/op/IsDerived.java b/src/org/python/antlr/op/IsDerived.java index 81ed57fa3..11e37938b 100644 --- a/src/org/python/antlr/op/IsDerived.java +++ b/src/org/python/antlr/op/IsDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/IsNot.java b/src/org/python/antlr/op/IsNot.java index edff4e839..a7dbcc35a 100644 --- a/src/org/python/antlr/op/IsNot.java +++ b/src/org/python/antlr/op/IsNot.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.IsNot", base = cmpop.class) diff --git a/src/org/python/antlr/op/IsNotDerived.java b/src/org/python/antlr/op/IsNotDerived.java index 923895f6d..e5e5a02f1 100644 --- a/src/org/python/antlr/op/IsNotDerived.java +++ b/src/org/python/antlr/op/IsNotDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/LShift.java b/src/org/python/antlr/op/LShift.java index 48a9d30cf..494a3bb6d 100644 --- a/src/org/python/antlr/op/LShift.java +++ b/src/org/python/antlr/op/LShift.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.LShift", base = operator.class) diff --git a/src/org/python/antlr/op/LShiftDerived.java b/src/org/python/antlr/op/LShiftDerived.java index 988263003..16a6d4edc 100644 --- a/src/org/python/antlr/op/LShiftDerived.java +++ b/src/org/python/antlr/op/LShiftDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Load.java b/src/org/python/antlr/op/Load.java index 06720da1c..abdb97555 100644 --- a/src/org/python/antlr/op/Load.java +++ b/src/org/python/antlr/op/Load.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Load", base = expr_context.class) diff --git a/src/org/python/antlr/op/LoadDerived.java b/src/org/python/antlr/op/LoadDerived.java index e4b0f9fe3..20cd8bf13 100644 --- a/src/org/python/antlr/op/LoadDerived.java +++ b/src/org/python/antlr/op/LoadDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Lt.java b/src/org/python/antlr/op/Lt.java index d95fe1c57..0c9e03ad7 100644 --- a/src/org/python/antlr/op/Lt.java +++ b/src/org/python/antlr/op/Lt.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Lt", base = cmpop.class) diff --git a/src/org/python/antlr/op/LtDerived.java b/src/org/python/antlr/op/LtDerived.java index 1affd43a5..5b1b44fc2 100644 --- a/src/org/python/antlr/op/LtDerived.java +++ b/src/org/python/antlr/op/LtDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/LtE.java b/src/org/python/antlr/op/LtE.java index d0a01f36e..1d0dd70c2 100644 --- a/src/org/python/antlr/op/LtE.java +++ b/src/org/python/antlr/op/LtE.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.LtE", base = cmpop.class) diff --git a/src/org/python/antlr/op/LtEDerived.java b/src/org/python/antlr/op/LtEDerived.java index 17de095ed..c3219ec44 100644 --- a/src/org/python/antlr/op/LtEDerived.java +++ b/src/org/python/antlr/op/LtEDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Mod.java b/src/org/python/antlr/op/Mod.java index 4ba9aaca8..eecef83d4 100644 --- a/src/org/python/antlr/op/Mod.java +++ b/src/org/python/antlr/op/Mod.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Mod", base = operator.class) diff --git a/src/org/python/antlr/op/ModDerived.java b/src/org/python/antlr/op/ModDerived.java index 213616564..b0517425e 100644 --- a/src/org/python/antlr/op/ModDerived.java +++ b/src/org/python/antlr/op/ModDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Mult.java b/src/org/python/antlr/op/Mult.java index 66070a663..68f813def 100644 --- a/src/org/python/antlr/op/Mult.java +++ b/src/org/python/antlr/op/Mult.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Mult", base = operator.class) diff --git a/src/org/python/antlr/op/MultDerived.java b/src/org/python/antlr/op/MultDerived.java index 07b5ba7fe..a260d9893 100644 --- a/src/org/python/antlr/op/MultDerived.java +++ b/src/org/python/antlr/op/MultDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Not.java b/src/org/python/antlr/op/Not.java index 8a186a9e8..65a62beb1 100644 --- a/src/org/python/antlr/op/Not.java +++ b/src/org/python/antlr/op/Not.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.unaryop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Not", base = unaryop.class) diff --git a/src/org/python/antlr/op/NotDerived.java b/src/org/python/antlr/op/NotDerived.java index 4d111e843..716987b3b 100644 --- a/src/org/python/antlr/op/NotDerived.java +++ b/src/org/python/antlr/op/NotDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/NotEq.java b/src/org/python/antlr/op/NotEq.java index c8a31edab..ec6abe553 100644 --- a/src/org/python/antlr/op/NotEq.java +++ b/src/org/python/antlr/op/NotEq.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.NotEq", base = cmpop.class) diff --git a/src/org/python/antlr/op/NotEqDerived.java b/src/org/python/antlr/op/NotEqDerived.java index fe08bedd1..b7e26f04d 100644 --- a/src/org/python/antlr/op/NotEqDerived.java +++ b/src/org/python/antlr/op/NotEqDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/NotIn.java b/src/org/python/antlr/op/NotIn.java index 3d32fba25..e8e347480 100644 --- a/src/org/python/antlr/op/NotIn.java +++ b/src/org/python/antlr/op/NotIn.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.cmpop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.NotIn", base = cmpop.class) diff --git a/src/org/python/antlr/op/NotInDerived.java b/src/org/python/antlr/op/NotInDerived.java index 971c20228..57304d4a3 100644 --- a/src/org/python/antlr/op/NotInDerived.java +++ b/src/org/python/antlr/op/NotInDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Or.java b/src/org/python/antlr/op/Or.java index 076ddd67f..c1eb6ea36 100644 --- a/src/org/python/antlr/op/Or.java +++ b/src/org/python/antlr/op/Or.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.boolop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Or", base = boolop.class) diff --git a/src/org/python/antlr/op/OrDerived.java b/src/org/python/antlr/op/OrDerived.java index 5b533f313..7d592289e 100644 --- a/src/org/python/antlr/op/OrDerived.java +++ b/src/org/python/antlr/op/OrDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Param.java b/src/org/python/antlr/op/Param.java index 4fb4d51c5..0c02a183b 100644 --- a/src/org/python/antlr/op/Param.java +++ b/src/org/python/antlr/op/Param.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Param", base = expr_context.class) diff --git a/src/org/python/antlr/op/ParamDerived.java b/src/org/python/antlr/op/ParamDerived.java index e0f72b249..4c0821c08 100644 --- a/src/org/python/antlr/op/ParamDerived.java +++ b/src/org/python/antlr/op/ParamDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Pow.java b/src/org/python/antlr/op/Pow.java index 8ee459fde..ca8254ee9 100644 --- a/src/org/python/antlr/op/Pow.java +++ b/src/org/python/antlr/op/Pow.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Pow", base = operator.class) diff --git a/src/org/python/antlr/op/PowDerived.java b/src/org/python/antlr/op/PowDerived.java index af0292e80..160e5757b 100644 --- a/src/org/python/antlr/op/PowDerived.java +++ b/src/org/python/antlr/op/PowDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/RShift.java b/src/org/python/antlr/op/RShift.java index ef1de8f6f..2725eb69c 100644 --- a/src/org/python/antlr/op/RShift.java +++ b/src/org/python/antlr/op/RShift.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.RShift", base = operator.class) diff --git a/src/org/python/antlr/op/RShiftDerived.java b/src/org/python/antlr/op/RShiftDerived.java index 240b1e2ee..1ba08bbc5 100644 --- a/src/org/python/antlr/op/RShiftDerived.java +++ b/src/org/python/antlr/op/RShiftDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Store.java b/src/org/python/antlr/op/Store.java index f32ca044e..f2e1c5019 100644 --- a/src/org/python/antlr/op/Store.java +++ b/src/org/python/antlr/op/Store.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.expr_context; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Store", base = expr_context.class) diff --git a/src/org/python/antlr/op/StoreDerived.java b/src/org/python/antlr/op/StoreDerived.java index 4931e23ff..f2e0b8609 100644 --- a/src/org/python/antlr/op/StoreDerived.java +++ b/src/org/python/antlr/op/StoreDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/Sub.java b/src/org/python/antlr/op/Sub.java index 6c3bd6e4f..c1dcfbbe6 100644 --- a/src/org/python/antlr/op/Sub.java +++ b/src/org/python/antlr/op/Sub.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.operator; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.Sub", base = operator.class) diff --git a/src/org/python/antlr/op/SubDerived.java b/src/org/python/antlr/op/SubDerived.java index b3dc01282..fa275bc52 100644 --- a/src/org/python/antlr/op/SubDerived.java +++ b/src/org/python/antlr/op/SubDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/UAdd.java b/src/org/python/antlr/op/UAdd.java index 15d56ff6f..52e83a1ed 100644 --- a/src/org/python/antlr/op/UAdd.java +++ b/src/org/python/antlr/op/UAdd.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.unaryop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.UAdd", base = unaryop.class) diff --git a/src/org/python/antlr/op/UAddDerived.java b/src/org/python/antlr/op/UAddDerived.java index 2639c571c..55c00b142 100644 --- a/src/org/python/antlr/op/UAddDerived.java +++ b/src/org/python/antlr/op/UAddDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/antlr/op/USub.java b/src/org/python/antlr/op/USub.java index 7e954aa2b..128461391 100644 --- a/src/org/python/antlr/op/USub.java +++ b/src/org/python/antlr/op/USub.java @@ -1,7 +1,6 @@ // Autogenerated AST node package org.python.antlr.op; -import org.python.antlr.AST; import org.python.antlr.base.unaryop; import org.python.antlr.PythonTree; import org.python.core.Py; @@ -11,7 +10,6 @@ import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "_ast.USub", base = unaryop.class) diff --git a/src/org/python/antlr/op/USubDerived.java b/src/org/python/antlr/op/USubDerived.java index 3c6227627..cde5a1ae8 100644 --- a/src/org/python/antlr/op/USubDerived.java +++ b/src/org/python/antlr/op/USubDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/compiler/ClassFile.java b/src/org/python/compiler/ClassFile.java index a9aaf3ba2..1c64ff53a 100644 --- a/src/org/python/compiler/ClassFile.java +++ b/src/org/python/compiler/ClassFile.java @@ -4,6 +4,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.io.File; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -42,19 +44,18 @@ public static String fixName(String n) { } return new String(c); } - public static void visitAnnotations(AnnotationVisitor av, Map fields) { for (Entryfield: fields.entrySet()) { visitAnnotation(av, field.getKey(), field.getValue()); } } - + // See org.objectweb.asm.AnnotationVisitor for details // TODO Support annotation annotations and annotation array annotations public static void visitAnnotation(AnnotationVisitor av, String fieldName, Object fieldValue) { Class fieldValueClass = fieldValue.getClass(); - + if (fieldValue instanceof Class) { av.visit(fieldName, Type.getType((Class)fieldValue)); } else if (fieldValueClass.isEnum()) { @@ -79,13 +80,14 @@ public ClassFile(String name) { public ClassFile(String name, String superclass, int access) { this(name, superclass, access, org.python.core.imp.NO_MTIME); } + public ClassFile(String name, String superclass, int access, long mtime) { this.name = fixName(name); this.superclass = fixName(superclass); this.interfaces = new String[0]; this.access = access; this.mtime = mtime; - + cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); methodVisitors = Collections.synchronizedList(new ArrayList()); fieldVisitors = Collections.synchronizedList(new ArrayList()); @@ -96,7 +98,9 @@ public void setSource(String name) { sfilename = name; } - public void addInterface(String name) throws IOException { + public void addInterface(String name) + throws IOException + { String[] new_interfaces = new String[interfaces.length+1]; System.arraycopy(interfaces, 0, new_interfaces, 0, interfaces.length); new_interfaces[interfaces.length] = name; @@ -111,15 +115,16 @@ public Code addMethod(String name, String type, int access) methodVisitors.add(pmv); return pmv; } + public Code addMethod(String name, String type, int access, String[] exceptions) - throws IOException - { - MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions); - Code pmv = new Code(mv, type, access); - methodVisitors.add(pmv); - return pmv; - } - + throws IOException + { + MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions); + Code pmv = new Code(mv, type, access); + methodVisitors.add(pmv); + return pmv; + } + public Code addMethod(String name, String type, int access, String[] exceptions, AnnotationDescr[]methodAnnotationDescrs, AnnotationDescr[][] parameterAnnotationDescrs) throws IOException @@ -134,7 +139,7 @@ public Code addMethod(String name, String type, int access, String[] exceptions, } av.visitEnd(); } - + // parameter annotations for (int i = 0; i < parameterAnnotationDescrs.length; i++) { for (AnnotationDescr ad: parameterAnnotationDescrs[i]) { @@ -145,12 +150,20 @@ public Code addMethod(String name, String type, int access, String[] exceptions, av.visitEnd(); } } - + Code pmv = new Code(mv, type, access); methodVisitors.add(pmv); return pmv; } - + + public void addFinalStringLiteral(String name, String value) + throws IOException + { + FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + + Opcodes.ACC_STATIC, name, ClassConstants.$str, null, value); + fieldVisitors.add(fv); + } + public void addClassAnnotation(AnnotationDescr annotationDescr) { AnnotationVisitor av = cw.visitAnnotation(annotationDescr.getName(), true); if (annotationDescr.hasFields()) { @@ -158,7 +171,7 @@ public void addClassAnnotation(AnnotationDescr annotationDescr) { } annotationVisitors.add(av); } - + public void addField(String name, String type, int access) throws IOException { @@ -190,7 +203,7 @@ public void endFields() fv.visitEnd(); } } - + public void endMethods() throws IOException { @@ -204,26 +217,44 @@ public void endMethods() public void endClassAnnotations() { for (AnnotationVisitor av: annotationVisitors) { av.visitEnd(); - } + } } - public void write(OutputStream stream) throws IOException { - cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, this.name, null, this.superclass, interfaces); + public void write(OutputStream stream) + throws IOException + { + String sfilenameShort = sfilename; + if (sfilename != null) { + try { + Path pth = new File("dist/Lib").toPath().normalize().toAbsolutePath(); + Path pth2 = new File(sfilename).toPath().normalize().toAbsolutePath(); + sfilenameShort = pth.relativize(pth2).toString(); + if (sfilenameShort.startsWith("..")) { + // prefer absolute path in this case + sfilenameShort = sfilename; + } + if (File.separatorChar != '/') { + // Make the path uniform on all platforms. We use POSIX- and URL-notation here. + sfilenameShort = sfilenameShort.replace(File.separatorChar, '/'); + } + } catch (Exception fe) {} + } + cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, this.name, null, this.superclass, interfaces); AnnotationVisitor av = cw.visitAnnotation("Lorg/python/compiler/APIVersion;", true); // XXX: should imp.java really house this value or should imp.java point into // org.python.compiler? - av.visit("value", new Integer(imp.getAPIVersion())); + av.visit("value", Integer.valueOf(imp.getAPIVersion())); av.visitEnd(); av = cw.visitAnnotation("Lorg/python/compiler/MTime;", true); - av.visit("value", new Long(mtime)); + av.visit("value", Long.valueOf(mtime)); av.visitEnd(); - if (sfilename != null) { + if (sfilenameShort != null) { av = cw.visitAnnotation("Lorg/python/compiler/Filename;", true); - av.visit("value", sfilename); + av.visit("value", sfilenameShort); av.visitEnd(); - cw.visitSource(sfilename, null); + cw.visitSource(sfilenameShort, null); } endClassAnnotations(); endFields(); diff --git a/src/org/python/compiler/Code.java b/src/org/python/compiler/Code.java index 173882bb0..c6ec2cf0a 100644 --- a/src/org/python/compiler/Code.java +++ b/src/org/python/compiler/Code.java @@ -22,7 +22,7 @@ public class Code extends MethodVisitor implements Opcodes { //XXX: I'd really like to get sig and access out of here since MethodVistitor // should already have this information. public Code(MethodVisitor mv, String sig, int access) { - super(ASM5); + super(ASM7); this.mv = mv; this.sig = sig; nlocals = -sigSize(sig, false); diff --git a/src/org/python/compiler/CodeCompiler.java b/src/org/python/compiler/CodeCompiler.java index 72083c51e..6920fbd12 100644 --- a/src/org/python/compiler/CodeCompiler.java +++ b/src/org/python/compiler/CodeCompiler.java @@ -105,7 +105,7 @@ public class CodeCompiler extends Visitor implements Opcodes, ClassConstants { - private static final Object Exit = new Integer(1); + private static final Object Exit = Integer.valueOf(1); private static final Object NoExit = null; private Module module; private Code code; @@ -183,7 +183,7 @@ public void setline(int line) throws Exception { } public void setline(PythonTree node) throws Exception { - setline(node.getLine()); + setline(node.getLineno()); } public void set(PythonTree node) throws Exception { @@ -509,7 +509,7 @@ public Object visitFunctionDef(FunctionDef node) throws Exception { scope.setup_closure(); scope.dump(); module.codeConstant(new Suite(node, node.getInternalBody()), name, true, className, false, - false, node.getLine(), scope, cflags).get(code); + false, node.getLineno(), scope, cflags).get(code); Str docStr = getDocStr(node.getInternalBody()); if (docStr != null) { @@ -2168,7 +2168,7 @@ public Object visitListComp(ListComp node) throws Exception { code.ldc("append"); code.invokevirtual(p(PyObject.class), "__getattr__", sig(PyObject.class, String.class)); - String tmp_append = "_[" + node.getLine() + "_" + node.getCharPositionInLine() + "]"; + String tmp_append = "_[" + node.getLineno() + "_" + node.getCol_offset() + "]"; java.util.List args = new ArrayList(); args.add(node.getInternalElt()); @@ -2312,7 +2312,7 @@ public Object visitLambda(Lambda node) throws Exception { scope.setup_closure(); scope.dump(); - module.codeConstant(retSuite, name, true, className, false, false, node.getLine(), scope, + module.codeConstant(retSuite, name, true, className, false, false, node.getLineno(), scope, cflags).get(code); if (!makeClosure(scope)) { @@ -2387,8 +2387,8 @@ public Object visitClassDef(ClassDef node) throws Exception { // Make code object out of suite module.codeConstant(new Suite(node, node.getInternalBody()), name, false, name, - getDocStr(node.getInternalBody()), true, false, node.getLine(), scope, cflags).get( - code); + getDocStr(node.getInternalBody()), true, false, node.getLineno(), scope, cflags) + .get(code); // Make class out of name, bases, and code if (!makeClosure(scope)) { @@ -2608,7 +2608,7 @@ private Object visitInternalGenerators(expr node, expr elt, java.util.List bod = new ArrayList(); bod.add(n); module.codeConstant(new Suite(node, bod), "", true, className, false, false, - node.getLine(), scope, cflags).get(code); + node.getLineno(), scope, cflags).get(code); code.aconst_null(); if (!makeClosure(scope)) { @@ -2681,7 +2681,7 @@ public Object visitGeneratorExp(GeneratorExp node) throws Exception { java.util.List bod = new ArrayList(); bod.add(n); module.codeConstant(new Suite(node, bod), "", true, className, false, false, - node.getLine(), scope, cflags).get(code); + node.getLineno(), scope, cflags).get(code); code.aconst_null(); if (!makeClosure(scope)) { diff --git a/src/org/python/compiler/LineNumberTable.java b/src/org/python/compiler/LineNumberTable.java index 67a074bd7..1ff22c347 100644 --- a/src/org/python/compiler/LineNumberTable.java +++ b/src/org/python/compiler/LineNumberTable.java @@ -7,8 +7,9 @@ import java.io.IOException; /** - * @Deprecated Not used. Delete in 2.6. + * @deprecated Not used. Delete in 2.6. */ +@Deprecated public class LineNumberTable { int attName; Vector lines; @@ -31,8 +32,8 @@ public void write(DataOutputStream stream) throws IOException { } public void addLine(int startpc, int lineno) { - lines.addElement(new Short((short) startpc)); - lines.addElement(new Short((short) lineno)); + lines.addElement(Short.valueOf((short) startpc)); + lines.addElement(Short.valueOf((short) lineno)); } public int length() { diff --git a/src/org/python/compiler/Module.java b/src/org/python/compiler/Module.java index 5a5180623..ff62c94f9 100644 --- a/src/org/python/compiler/Module.java +++ b/src/org/python/compiler/Module.java @@ -1,18 +1,27 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.compiler; +import static org.python.core.RegistryKey.PYTHON_CPYTHON; import static org.python.util.CodegenUtils.ci; import static org.python.util.CodegenUtils.p; import static org.python.util.CodegenUtils.sig; import java.io.IOException; import java.io.OutputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.io.File; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; +import java.util.Stack; import java.util.List; import org.objectweb.asm.Label; +import org.objectweb.asm.MethodTooLargeException; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.python.antlr.ParseException; @@ -21,14 +30,18 @@ import org.python.antlr.ast.Str; import org.python.antlr.ast.Suite; import org.python.antlr.base.mod; +import org.python.core.ClasspathPyImporter; import org.python.core.CodeBootstrap; import org.python.core.CodeFlag; import org.python.core.CodeLoader; import org.python.core.CompilerFlags; +import org.python.core.imp; import org.python.core.Py; import org.python.core.PyCode; +import org.python.core.PyBytecode; import org.python.core.PyComplex; import org.python.core.PyException; +import org.python.core.PyFile; import org.python.core.PyFloat; import org.python.core.PyFrame; import org.python.core.PyFunctionTable; @@ -40,6 +53,9 @@ import org.python.core.PyString; import org.python.core.PyUnicode; import org.python.core.ThreadState; +import org.python.modules._marshal; + + class PyIntegerConstant extends Constant implements ClassConstants, Opcodes { @@ -76,8 +92,6 @@ public boolean equals(Object o) { class PyFloatConstant extends Constant implements ClassConstants, Opcodes { - private static final double ZERO = 0.0; - final double value; PyFloatConstant(double value) { @@ -86,7 +100,7 @@ class PyFloatConstant extends Constant implements ClassConstants, Opcodes { @Override void get(Code c) throws IOException { - c.ldc(new Double(value)); + c.ldc(Double.valueOf(value)); c.invokestatic(p(Py.class), "newFloat", sig(PyFloat.class, Double.TYPE)); } @@ -121,7 +135,7 @@ class PyComplexConstant extends Constant implements ClassConstants, Opcodes { @Override void get(Code c) throws IOException { - c.ldc(new Double(value)); + c.ldc(Double.valueOf(value)); c.invokestatic(p(Py.class), "newImaginary", sig(PyComplex.class, Double.TYPE)); } @@ -297,6 +311,10 @@ class PyCodeConstant extends Constant implements ClassConstants, Opcodes { fname = "f$" + id; } // XXX: is fname needed at all, or should we just use "name"? + // It is needed to disambiguate functions and methods with + // same name, but in different classes. The function-fields + // and PyCode-fields that Jython generates don't use fully + // qualified names. So fname is used. this.name = fname; // !classdef only @@ -338,7 +356,7 @@ private List toNameAr(List names, boolean nullok) { return nameArray; } - private boolean isJavaIdentifier(String s) { + public static boolean isJavaIdentifier(String s) { char[] chars = s.toCharArray(); if (chars.length == 0) { return false; @@ -414,6 +432,23 @@ void put(Code c) throws IOException { } } +class PyBytecodeConstant extends Constant implements ClassConstants, Opcodes { + PyBytecodeConstant(String name, String className, CompilerFlags cflags, + Module module) throws Exception { + super(); + this.module = module; + this.name = name; + } + + @Override + void get(Code c) throws IOException { + c.getstatic(module.classfile.name, name, ci(PyCode.class)); + } + + @Override + void put(Code c) throws IOException { + } +} public class Module implements Opcodes, ClassConstants, CompilationContext { @@ -433,6 +468,9 @@ public class Module implements Opcodes, ClassConstants, CompilationContext { /** The pool of Python Constants */ Hashtable constants; + /** Table of oversized methods represented as CPython bytecode. */ + protected Hashtable oversized_methods = null; + public Module(String name, String filename, boolean linenumbers) { this(name, filename, linenumbers, org.python.core.imp.NO_MTIME); } @@ -495,25 +533,33 @@ Constant longConstant(String value) { return findConstant(new PyLongConstant(value)); } - PyCodeConstant codeConstant(mod tree, String name, boolean fast_locals, String className, + Constant codeConstant(mod tree, String name, boolean fast_locals, String className, boolean classBody, boolean printResults, int firstlineno, ScopeInfo scope, CompilerFlags cflags) throws Exception { return codeConstant(tree, name, fast_locals, className, null, classBody, printResults, firstlineno, scope, cflags); } - PyCodeConstant codeConstant(mod tree, String name, boolean fast_locals, String className, + Constant codeConstant(mod tree, String name, boolean fast_locals, String className, Str classDoc, boolean classBody, boolean printResults, int firstlineno, ScopeInfo scope, CompilerFlags cflags) throws Exception { - PyCodeConstant code = new PyCodeConstant(tree, name, fast_locals, className, classBody, // + if (oversized_methods != null && oversized_methods.containsKey(name+firstlineno)) { + // For now this only declares the field. + // PyBytecodeConstant is just a dummy to allow the caller to work properly. + // It is intentionally not added to codes, because it doesn't participate in + // FunctionTable and doesn't mess up addFunctions and addConstants this way. + PyBytecodeConstant bcode = new PyBytecodeConstant( + oversized_methods.get(name+firstlineno), className, cflags, this); + classfile.addField(bcode.name, ci(PyCode.class), ACC_PUBLIC | ACC_STATIC); + return bcode; + } + PyCodeConstant code = new PyCodeConstant(tree, name, fast_locals, className, classBody, printResults, firstlineno, scope, cflags, this); codes.add(code); CodeCompiler compiler = new CodeCompiler(this, printResults); - - Code c = classfile.addMethod(code.fname, // + Code c = classfile.addMethod(code.fname, sig(PyObject.class, PyFrame.class, ThreadState.class), ACC_PUBLIC); - compiler.parse(tree, c, fast_locals, className, classDoc, classBody, scope, cflags); return code; } @@ -533,7 +579,7 @@ public void addRunnable() throws IOException { } public void addMain() throws IOException { - Code c = classfile.addMethod("main", // + Code c = classfile.addMethod("main", sig(Void.TYPE, String[].class), ACC_PUBLIC | ACC_STATIC); c.new_(classfile.name); c.dup(); @@ -548,7 +594,7 @@ public void addMain() throws IOException { } public void addBootstrap() throws IOException { - Code c = classfile.addMethod(CodeLoader.GET_BOOTSTRAP_METHOD_NAME, // + Code c = classfile.addMethod(CodeLoader.GET_BOOTSTRAP_METHOD_NAME, sig(CodeBootstrap.class), ACC_PUBLIC | ACC_STATIC); c.ldc(Type.getType("L" + classfile.name + ";")); c.invokestatic(p(PyRunnableBootstrap.class), PyRunnableBootstrap.REFLECTION_METHOD_NAME, @@ -560,15 +606,14 @@ void addConstants(Code c) throws IOException { classfile.addField("self", "L" + classfile.name + ";", ACC_STATIC); c.aload(0); c.putstatic(classfile.name, "self", "L" + classfile.name + ";"); - Enumeration e = constants.elements(); + Enumeration e = constants.elements(); while (e.hasMoreElements()) { - Constant constant = (Constant)e.nextElement(); + Constant constant = e.nextElement(); constant.put(c); } - for (int i = 0; i < codes.size(); i++) { - PyCodeConstant pyc = codes.get(i); + for (PyCodeConstant pyc: codes) { pyc.put(c); } @@ -576,29 +621,31 @@ void addConstants(Code c) throws IOException { } public void addFunctions() throws IOException { - Code code = classfile.addMethod("call_function", // + Code code = classfile.addMethod("call_function", sig(PyObject.class, Integer.TYPE, PyFrame.class, ThreadState.class), ACC_PUBLIC); - code.aload(0); // this - code.aload(2); // frame - code.aload(3); // thread state - Label def = new Label(); - Label[] labels = new Label[codes.size()]; - int i; - for (i = 0; i < labels.length; i++) { - labels[i] = new Label(); - } + if (!codes.isEmpty()) { + code.aload(0); // this + code.aload(2); // frame + code.aload(3); // thread state + Label def = new Label(); + Label[] labels = new Label[codes.size()]; + int i; + for (i = 0; i < labels.length; i++) { + labels[i] = new Label(); + } - // Get index for function to call - code.iload(1); - code.tableswitch(0, labels.length - 1, def, labels); - for (i = 0; i < labels.length; i++) { - code.label(labels[i]); - code.invokevirtual(classfile.name, (codes.get(i)).fname, - sig(PyObject.class, PyFrame.class, ThreadState.class)); - code.areturn(); + // Get index for function to call + code.iload(1); + code.tableswitch(0, labels.length - 1, def, labels); + for (i = 0; i < labels.length; i++) { + code.label(labels[i]); + code.invokevirtual(classfile.name, (codes.get(i)).fname, + sig(PyObject.class, PyFrame.class, ThreadState.class)); + code.areturn(); + } + code.label(def); } - code.label(def); // Should probably throw internal exception here code.aconst_null(); @@ -641,7 +688,7 @@ public void error(String msg, boolean err, PythonTree node) throws Exception { if (!err) { try { Py.warning(Py.SyntaxWarning, msg, (sfilename != null) ? sfilename : "?", - node.getLine(), null, Py.None); + node.getLineno(), null, Py.None); return; } catch (PyException e) { if (!e.match(Py.SyntaxWarning)) { @@ -658,10 +705,8 @@ public static void compile(mod node, OutputStream ostream, String name, String f org.python.core.imp.NO_MTIME); } - public static void compile(mod node, OutputStream ostream, String name, String filename, - boolean linenumbers, boolean printResults, CompilerFlags cflags, long mtime) - throws Exception { - Module module = new Module(name, filename, linenumbers, mtime); + protected static void _module_init(mod node, Module module, boolean printResults, + CompilerFlags cflags) throws Exception { if (cflags == null) { cflags = new CompilerFlags(); } @@ -670,10 +715,380 @@ public static void compile(mod node, OutputStream ostream, String name, String f // Add __doc__ if it exists - Constant main = module.codeConstant(node, "", false, null, false, // + Constant main = module.codeConstant(node, "", false, null, false, printResults, 0, module.getScopeInfo(node), cflags); module.mainCode = main; - module.write(ostream); + } + + // Error message formats required by loadPyBytecode + private static String TRIED_CREATE_PYC_MSG = + "\nJython tried to create a pyc-file by executing\n %s\nwhich failed because %s"; + private static String LARGE_METHOD_MSG = "Module or method too large in `%s`."; + private static String PLEASE_PROVIDE_MSG = + "\n\nPlease provide a CPython 2.7 bytecode file (.pyc), e.g. run" + + "\n python -m py_compile %s"; + private static String CPYTHON_CMD_MSG = + "\n\nAlternatively, specify a CPython 2.7 command via the " // + + PYTHON_CPYTHON + " property, e.g.:" // + + "\n jython -D" + PYTHON_CPYTHON + "=python" // + + "\nor (e.g. for pip) through the environment variable JYTHON_OPTS:" // + + "\n export JYTHON_OPTS=\"-D" + PYTHON_CPYTHON + + "=python\"\n"; + + private static PyBytecode loadPyBytecode(String filename, boolean try_cpython) + throws RuntimeException { + if (filename.startsWith(ClasspathPyImporter.PYCLASSPATH_PREFIX)) { + ClassLoader cld = Py.getSystemState().getClassLoader(); + if (cld == null) { + cld = imp.getParentClassLoader(); + } + URL py_url = + cld.getResource(filename.replace(ClasspathPyImporter.PYCLASSPATH_PREFIX, "")); + if (py_url != null) { + filename = py_url.getPath(); + } else { + // Should never happen, but let's play it safe and treat this case. + throw new RuntimeException(String.format(LARGE_METHOD_MSG, filename) + + "but couldn't resolve that filename within classpath.\n" + + "Make sure the source file is at a proper location."); + } + } + + String pyc_filename = filename + "c"; + File pyc_file = new File(pyc_filename); + if (pyc_file.exists()) { + PyFile f = new PyFile(pyc_filename, "rb", 4096); + byte[] bts = f.read(8).toBytes(); + int magic = (bts[1] << 8) & 0x0000FF00 | (bts[0] << 0) & 0x000000FF; + // int mtime_pyc = (bts[7]<<24) & 0xFF000000 | + // (bts[6]<<16) & 0x00FF0000 | + // (bts[5]<< 8) & 0x0000FF00 | + // (bts[4]<< 0) & 0x000000FF; + if (magic != 62211) { // check Python 2.7 bytecode + throw new RuntimeException( + String.format(LARGE_METHOD_MSG, filename) // + + "\n'" + pyc_filename + "' is not CPython 2.7 bytecode." // + + String.format(PLEASE_PROVIDE_MSG, filename)); + } + _marshal.Unmarshaller un = new _marshal.Unmarshaller(f); + PyObject code = un.load(); + f.close(); + if (code instanceof PyBytecode) { + return (PyBytecode) code; + } + throw new RuntimeException(String.format(LARGE_METHOD_MSG, filename) // + + "\n'" + pyc_filename + "' contains invalid bytecode." + + String.format(PLEASE_PROVIDE_MSG, filename)); + + } else { + String CPython_command = System.getProperty(PYTHON_CPYTHON); + if (try_cpython && CPython_command != null) { + // check version... + String command_ver = CPython_command + " --version"; + String command = CPython_command + " -m py_compile " + filename; + Exception exc = null; + int result = 0; + String reason; + try { + Process p = Runtime.getRuntime().exec(command_ver); + // Python 2.7 writes version to error-stream for some reason: + BufferedReader br = + new BufferedReader(new InputStreamReader(p.getErrorStream())); + String cp_version = br.readLine(); + while (br.readLine() != null) {} + br.close(); + if (cp_version == null) { + // Also try input-stream as fallback, just in case... + br = new BufferedReader(new InputStreamReader(p.getInputStream())); + cp_version = br.readLine(); + while (br.readLine() != null) {} + br.close(); + } + result = p.waitFor(); + if (!cp_version.startsWith("Python 2.7.")) { + reason = cp_version + " has been provided, but 2.7.x is required."; + throw new RuntimeException(String.format(LARGE_METHOD_MSG, filename) + + String.format(TRIED_CREATE_PYC_MSG, command, reason) + + String.format(PLEASE_PROVIDE_MSG, filename) + CPYTHON_CMD_MSG); + } + } catch (InterruptedException | IOException e) { + exc = e; + } + + if (exc == null && result == 0) { + try { + Process p = Runtime.getRuntime().exec(command); + result = p.waitFor(); + if (result == 0) { + return loadPyBytecode(filename, false); + } + } catch (InterruptedException | IOException e) { + exc = e; + } + } + reason = exc != null ? "of " + exc.toString() : "of a bad return: " + result; + String exc_msg = String.format(LARGE_METHOD_MSG, filename) + + String.format(TRIED_CREATE_PYC_MSG, command, reason) + + String.format(PLEASE_PROVIDE_MSG, filename) + CPYTHON_CMD_MSG; + throw exc != null ? new RuntimeException(exc_msg, exc) + : new RuntimeException(exc_msg); + } else { + throw new RuntimeException(String.format(LARGE_METHOD_MSG, filename) + + String.format(PLEASE_PROVIDE_MSG, filename) + CPYTHON_CMD_MSG); + } + } + } + + private static String serializePyBytecode(PyBytecode btcode) throws java.io.IOException { + // For some reason we cannot do this using _marshal: + /* + cStringIO.StringIO buf = cStringIO.StringIO(); + _marshal.Marshaller marsh = new _marshal.Marshaller(buf); + marsh.dump(largest_m_code); + String code_str = buf.getvalue().asString(); + + _marshal.Unmarshaller un2 = new _marshal.Unmarshaller(cStringIO.StringIO(code_str)); + PyBytecode code = (PyBytecode) un2.load(); + + This says 'ValueError: bad marshal data' + Maybe the issue is actually with cStringIO, because bytecode-marshalling uses + bytes not directly suitable as String-values. cStringIO does not use Base64 or + something, but rather supports only string-compatible data. + */ + // so we use Java-serialization... + + // serialize the object + ByteArrayOutputStream bo = new ByteArrayOutputStream(); + ObjectOutputStream so = new ObjectOutputStream(bo); + so.writeObject(btcode); + so.flush(); + // From Java 8 use: String code_str = Base64.getEncoder().encodeToString(bo.toByteArray()); + String code_str = base64encodeToString(bo.toByteArray()); + so.close(); + bo.close(); + return code_str; + } + + /** + * Implement a simplified base64 encoding compatible with the decoding in BytecodeLoader. This + * encoder adds no '=' padding or line-breaks. equivalent to + * {@code binascii.b2a_base64(bytes).rstrip('=\n')}. + * + * @param data to encode + * @return the string encoding the data + */ + private static String base64encodeToString(byte[] data) { + + final int N = data.length; + int tail = N % 3; + + StringBuilder chars = new StringBuilder(((N / 3) + 1) * 4); + + // Process bytes in blocks of three + int b = 0, quantum; + while (b <= N - 3) { + // Process [b:b+3] + quantum = ((data[b++] & 0xff) << 16) + ((data[b++] & 0xff) << 8) + (data[b++] & 0xff); + chars.append(base64enc[quantum >> 18]); + chars.append(base64enc[(quantum >> 12) & 0x3f]); + chars.append(base64enc[(quantum >> 6) & 0x3f]); + chars.append(base64enc[quantum & 0x3f]); + } + + // Process the tail bytes + if (tail >= 1) { + quantum = ((data[b++] & 0xff) << 8); + if (tail == 2) { + quantum += data[b++] & 0xff; + } + chars.append(base64enc[quantum >> 10]); + chars.append(base64enc[(quantum >> 4) & 0x3f]); + if (tail == 2) { + chars.append(base64enc[(quantum << 2) & 0x3f]); + } + } + + return chars.toString(); + } + + /** Look-up table for {@link #base64encodeToString(byte[])}. */ + private static final char[] base64enc = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + + private static final int maxLiteral = 65535; + + /** + * This method stores Base64 encoded Python byte code in one or more String literals. + *

    + * While Java String objects are limited only by the address range of arrays, the class file + * standard only supports literals representable in at most 65535 bytes of modified UTF-8. This + * method us used only with base64 Strings (therefore ASCII without nulls) and so each character + * occupies exactly 1 byte in the class file after encoding to UTF-8. + *

    + * To work within the 65535 byte limitation, the {@code code_str} is split into several literals + * with the following naming-scheme: + *

      + *
    • The marker-interface 'ContainsPyBytecode' indicates that a class contains (static final) + * literals of the following scheme: + *
    • a prefix of '___' indicates a bytecode-containing string literal + *
    • a number indicating the number of parts follows + *
    • '0_' indicates that no splitting occurred + *
    • otherwise another number follows, naming the index of the literal + *
    • indexing starts at 0 + *
    + * Examples: + *
      + *
    • {@code ___0_method1} contains bytecode for method1 + *
    • {@code ___2_0_method2} contains first part of method2's bytecode + *
    • {@code ___2_1_method2} contains second part of method2's bytecode + *
    + * Note that this approach is provisional. In future, Jython might contain the bytecode directly + * as bytecode-objects. The current approach was feasible with far less complicated JVM + * bytecode-manipulation, but needs special treatment after class-loading. + * + * @param name of the method or function being generated + * @param code_str Base64 encoded CPython byte code + * @param module currently being defined as a class file + * @throws java.io.IOException + */ + private static void insert_code_str_to_classfile(String name, String code_str, Module module) + throws java.io.IOException { + if (code_str.length() <= maxLiteral) { + // This can go as a single literal + module.classfile.addFinalStringLiteral("___0_" + name, code_str); + } else { + // We need to split the code into several literals. + int splits = code_str.length() / maxLiteral; + if (code_str.length() % maxLiteral > 0) { + ++splits; + } + int pos = 0, i = 0; + for (; pos + maxLiteral <= code_str.length(); ++i) { + module.classfile.addFinalStringLiteral("___" + splits + "_" + i + "_" + name, + code_str.substring(pos, pos + maxLiteral)); + pos += maxLiteral; + } + if (i < splits) { + module.classfile.addFinalStringLiteral("___" + splits + "_" + i + "_" + name, + code_str.substring(pos)); + } + } + } + + /** + * Create and write a Python module as a Java class file. + * + * @param node AST of the module to write + * @param ostream stream onto which to write it + * @param name + * @param filename + * @param linenumbers + * @param printResults + * @param cflags + * @param mtime + * @throws Exception + */ + public static void compile(mod node, OutputStream ostream, String name, String filename, + boolean linenumbers, boolean printResults, CompilerFlags cflags, long mtime) + throws Exception { + + try { + Module module = new Module(name, filename, linenumbers, mtime); + _module_init(node, module, printResults, cflags); + module.write(ostream); + + } catch (MethodTooLargeException re) { + PyBytecode btcode = loadPyBytecode(filename, true); + int thresh = 22000; + /* + * No idea, how to determine at this point if a method is oversized, so we just try a + * threshold regarding Python code-length, while JVM restriction is actually about Java + * bytecode length. Anyway; given that code-lengths are strongly related, this should + * work well enough. + */ + while (true) { // Always enjoy to write a line like this :) + try { + List largest_m_codes = new ArrayList<>(); + Stack buffer = new Stack<>(); + // HashSet allCodes = new HashSet<>(); + buffer.push(btcode); + // allCodes.add(btcode); + + while (!buffer.isEmpty()) { + /* + * Probably this cannot yield cycles, so cycle-proof stuff is out-commented + * for now. (everything regarding 'allCodes') + */ + PyBytecode bcode = buffer.pop(); + if (bcode.co_code.length > thresh) { + largest_m_codes.add(bcode); + } else { + /* + * If a function needs to be represented as CPython bytecode, we create + * all inner PyCode-items (classes, functions, methods) also as CPython + * bytecode implicitly, so no need to look at them individually. Maybe + * we can later optimize this such that inner methods can be + * JVM-bytecode as well (if not oversized themselves). + */ + for (PyObject item : bcode.co_consts) { + if (item instanceof PyBytecode /* && !allCodes.contains(item) */) { + PyBytecode mpbc = (PyBytecode) item; + buffer.push(mpbc); + // allCodes.add(mpbc); + } + } + } + } + + Module module = new Module(name, filename, linenumbers, mtime); + + module.oversized_methods = new Hashtable<>(largest_m_codes.size()); + int ov_id = 0; + String name_id; + + for (PyBytecode largest_m_code : largest_m_codes) { + if (!PyCodeConstant.isJavaIdentifier(largest_m_code.co_name)) { + name_id = "f$_" + ov_id++; + } else { + name_id = largest_m_code.co_name + "$_" + ov_id++; + } + if (largest_m_code.co_name.equals("")) { + /* + * In Jython's opinion module begins at line 0 (while CPython reports + * line 1) + */ + module.oversized_methods.put(largest_m_code.co_name + 0, name_id); + } else { + module.oversized_methods.put( + largest_m_code.co_name + largest_m_code.co_firstlineno, + name_id); + } + + String code_str = serializePyBytecode(largest_m_code); + insert_code_str_to_classfile(name_id, code_str, module); + } + + module.classfile.addInterface(p(org.python.core.ContainsPyBytecode.class)); + + _module_init(node, module, printResults, cflags); + module.write(ostream); + + break; + + } catch (MethodTooLargeException e) { + thresh -= 1000; + } + if (thresh < 10000) { + /* + * This value should be well feasible by JVM-bytecode, so something else must be + * wrong. + */ + throw new RuntimeException( + "For unknown reason, too large method code couldn't be resolved" + + "\nby PyBytecode-approach:\n" + filename); + } + } + } } public void emitNum(Num node, Code code) throws Exception { @@ -720,7 +1135,7 @@ public boolean emitPrimitiveArraySetters(java.util.List no code.iconst(n); code.anewarray(p(PyObject.class)); for (int i = 0; i < num_setters; i++) { - Code setter = this.classfile.addMethod("set$$" + setter_count, // + Code setter = this.classfile.addMethod("set$$" + setter_count, sig(Void.TYPE, PyObject[].class), ACC_STATIC | ACC_PRIVATE); for (int j = 0; (j < MAX_SETTINGS_PER_SETTER) diff --git a/src/org/python/compiler/ProxyMaker.java b/src/org/python/compiler/ProxyMaker.java index 5fac4256b..10acf6c8d 100644 --- a/src/org/python/compiler/ProxyMaker.java +++ b/src/org/python/compiler/ProxyMaker.java @@ -16,7 +16,6 @@ import static org.python.util.CodegenUtils.p; import static org.python.util.CodegenUtils.sig; - public class ProxyMaker extends ProxyCodeHelpers implements ClassConstants, Opcodes { protected final Class superclass; @@ -33,8 +32,7 @@ public class ProxyMaker extends ProxyCodeHelpers implements ClassConstants, Opco * org.python.proxies.(superclassName) with superclass as an * implemented interface or extended class, depending on the its type. * - * @deprecated - Use {@link ProxyMaker#ProxyMaker(String, Class, Class[]) - + * @deprecated - Use {@link ProxyMaker#ProxyMaker(String, Class, Class[])} */ @Deprecated public ProxyMaker(String superclassName, Class superclass) { @@ -265,8 +263,9 @@ public void callMethod(Code code, doNullReturn(code, ret); code.freeLocal(excLocal); - if (exception == Throwable.class) + if (exception == Throwable.class) { throwableFound = true; + } } if (!throwableFound) { @@ -293,7 +292,7 @@ public void addMethod(Method method, int access) throws Exception { addMethod(method.getName(), method.getReturnType(), method.getParameterTypes(), method.getExceptionTypes(), access, method.getDeclaringClass()); } - + /** * Adds a method of the given name to the class being implemented. If * declaringClass is null, the generated method will expect to find an object of @@ -310,21 +309,20 @@ public void addMethod(String name, addMethod(name, name, ret, parameters, exceptions, access, declaringClass, null, null); } - + /** * Generates and adds a proxy method to the proxy class - * - * @param name: name of the java method - * @param pyName: name of the python method to which the java method - * proxies (useful for clamped objects) - * - * @param ret: return type - * @param parameters: parameter types - * @param exceptions: throwable exception types + * + * @param name of the java method + * @param pyName name of the python method to which the java method proxies (useful for clamped + * objects) + * @param ret return type + * @param parameters parameter types + * @param exceptions throwable exception types * @param access * @param declaringClass - * @param methodAnnotations: method annotations - * @param parameterAnnotations: parameter annotations + * @param methodAnnotations method annotations + * @param parameterAnnotations parameter annotations * @throws Exception */ public void addMethod(String name, @@ -337,7 +335,7 @@ public void addMethod(String name, AnnotationDescr[] methodAnnotations, AnnotationDescr[][]parameterAnnotations) throws Exception { boolean isAbstract = false; - + if (Modifier.isAbstract(access)) { access = access & ~Modifier.ABSTRACT; isAbstract = true; @@ -400,7 +398,7 @@ public void addMethod(String name, doNullReturn(code, ret); } } - + /** * A constructor that is also a method (!) */ @@ -412,7 +410,7 @@ public void addConstructorMethodCode(String pyName, Code code) throws Exception { code.aload(0); code.ldc(pyName); - + int tmp = code.getLocal("org/python/core/PyObject"); code.invokestatic("org/python/compiler/ProxyMaker", "findPython", makeSig($pyObj, $pyProxy, $str)); @@ -421,7 +419,7 @@ public void addConstructorMethodCode(String pyName, callMethod(code, "", parameters, Void.TYPE, exceptions); } - + private String methodString(Method m) { StringBuffer buf = new StringBuffer(m.getName()); buf.append(":"); @@ -500,7 +498,7 @@ public void addConstructors(Class c) throws Exception { addConstructor(name, parameters, Void.TYPE, makeSig(Void.TYPE, parameters), access); } } - + protected void addClassAnnotation(AnnotationDescr annotation) { classfile.addClassAnnotation(annotation); } @@ -635,21 +633,21 @@ public void build() throws Exception { addProxy(); visitConstructors(); classfile.addInterface("org/python/core/PyProxy"); - + visitClassAnnotations(); visitMethods(); doConstants(); addClassDictInit(); } - + /** * Visits all methods declared on the given class and classes in its inheritance hierarchy. * Methods visible to subclasses are added to seen. */ protected void visitMethods(Class klass) throws Exception { for (Method method : klass.getDeclaredMethods()) { - - + + // make sure we have only one name + signature pair available per method if (!namesAndSigs.add(methodString(method))) { continue; @@ -689,9 +687,10 @@ protected void visitMethods(Class klass) throws Exception { } /** - * Called for every method on the proxy's superclass and interfaces that can be overriden by the - * proxy class. If the proxy wants to perform Python lookup and calling for the method, - * {@link #addMethod(Method)} should be called. For abstract methods, addMethod must be called. + * Called for every method on the proxy's superclass and interfaces that can be overridden by + * the proxy class. If the proxy wants to perform Python lookup and calling, + * {@link #addMethod(Method, int)} or one of its more complex forms should be called. For + * abstract methods, {@code addMethod} must be called. */ protected void visitMethod(Method method) throws Exception { addMethod(method, method.getModifiers()); @@ -708,14 +707,14 @@ protected void visitMethods() throws Exception { visitMethods(iface); } } - + /** Adds a constructor that calls through to superclass. */ protected void addConstructor(Class[] parameters, int access) throws Exception { String sig = makeSig(Void.TYPE, parameters); Code code = classfile.addMethod("", sig, access); callSuper(code, "", mapClass(superclass), parameters, Void.TYPE, true); } - + /** * Called for every constructor on the proxy's superclass that can be overridden by * the proxy class. @@ -747,16 +746,15 @@ protected void callInitProxy(Class[] parameters, Code code) throws Exception code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr), false); code.visitInsn(RETURN); } - + /** * Visits constructors from this proxy's superclass. */ protected void visitConstructors() throws Exception { addConstructors(superclass); } - + protected void visitClassAnnotations() throws Exception { // ProxyMaker itself does nothing with class annotations for now } - } diff --git a/src/org/python/compiler/ScopeInfo.java b/src/org/python/compiler/ScopeInfo.java index 863f5bf9e..381d12b3e 100644 --- a/src/org/python/compiler/ScopeInfo.java +++ b/src/org/python/compiler/ScopeInfo.java @@ -1,12 +1,16 @@ +// (C) Copyright 2019 Jython Developers // (C) Copyright 2001 Samuele Pedroni +// Licensed to the PSF under a Contributor Agreement package org.python.compiler; import java.util.Enumeration; +import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.Map; -import java.util.Hashtable; import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; import org.python.antlr.ParseException; import org.python.antlr.PythonTree; @@ -15,38 +19,53 @@ public class ScopeInfo extends Object implements ScopeConstants { + static final Logger LOGGER = Logger.getLogger("org.python.compiler"); + public PythonTree scope_node; public String scope_name; public int level; public int func_level; public void dump() { // for debugging - if (org.python.core.Options.verbose < org.python.core.Py.DEBUG) - return; - for(int i=0; i entry : tbl.entrySet()) { - String name = entry.getKey(); - SymInfo info = entry.getValue(); - int flags = info.flags; - System.err.print(name); - if ((flags&BOUND) != 0) System.err.print('='); - // func scope global (affect nested scopes) - // vs. class scope global - if ((flags&NGLOBAL) != 0) System.err.print('G'); - else if ((flags&CLASS_GLOBAL) != 0) System.err.print('g'); - if ((flags&PARAM) != 0) System.err.print('P'); - else if ((flags&FROM_PARAM) != 0) System.err.print('p'); - if ((flags&CELL) != 0) System.err.print('!'); - if ((flags&FREE) != 0) System.err.print(",f"); - System.err.print(" "); + if (LOGGER.isLoggable(Level.FINE)) { + StringBuilder m = new StringBuilder(100); + for (int i = 0; i < level; i++) { + m.append(' '); + } + m.append(((kind != CLASSSCOPE) ? scope_name : "class " + scope_name) + ": "); + for (Map.Entry entry : tbl.entrySet()) { + String name = entry.getKey(); + SymInfo info = entry.getValue(); + int flags = info.flags; + m.append(name); + if ((flags & BOUND) != 0) { + m.append('='); + } + // func scope global (affect nested scopes) vs. class scope global + if ((flags & NGLOBAL) != 0) { + m.append('G'); + } else if ((flags & CLASS_GLOBAL) != 0) { + m.append('g'); + } + if ((flags & PARAM) != 0) { + m.append('P'); + } else if ((flags & FROM_PARAM) != 0) { + m.append('p'); + } + if ((flags & CELL) != 0) { + m.append('!'); + } + if ((flags & FREE) != 0) { + m.append(",f"); + } + m.append(' '); + } + LOGGER.fine(m.toString()); } - System.err.println(); } - public ScopeInfo(String name, PythonTree node, int level, int kind, - int func_level, ArgListCompiler ac) { + public ScopeInfo(String name, PythonTree node, int level, int kind, int func_level, + ArgListCompiler ac) { scope_name = name; scope_node = node; this.level = level; @@ -73,22 +92,22 @@ public ScopeInfo(String name, PythonTree node, int level, int kind, public int addGlobal(String name) { // global kind = func vs. class - int global = kind==CLASSSCOPE?CLASS_GLOBAL:NGLOBAL; + int global = kind == CLASSSCOPE ? CLASS_GLOBAL : NGLOBAL; SymInfo info = tbl.get(name); if (info == null) { - tbl.put(name,new SymInfo(global|BOUND)); + tbl.put(name, new SymInfo(global | BOUND)); return -1; } int prev = info.flags; - info.flags |= global|BOUND; + info.flags |= global | BOUND; return prev; } public int local = 0; public void addParam(String name) { -//System.out.println("addParam " + name); - tbl.put(name, new SymInfo(PARAM|BOUND,local++)); + // System.out.println("addParam " + name); + tbl.put(name, new SymInfo(PARAM | BOUND, local++)); names.addElement(name); } @@ -116,7 +135,7 @@ public void addUsed(String name) { private final static Object PRESENT = new Object(); - public Hashtable inner_free = new Hashtable(); + public Hashtable inner_free = new Hashtable(); public Vector cellvars = new Vector(); @@ -128,10 +147,11 @@ public void addUsed(String name) { public ScopeInfo up; - //Resolve the names used in the given scope, and mark any freevars used in the up scope + // Resolve the names used in the given scope, and mark any freevars used in the up scope public void cook(ScopeInfo up, int distance, CompilationContext ctxt) throws Exception { - if(up == null) + if (up == null) { return; // top level => nop + } this.up = up; this.distance = distance; boolean func = kind == FUNCSCOPE; @@ -139,23 +159,26 @@ public void cook(ScopeInfo up, int distance, CompilationContext ctxt) throws Exc cell = 0; boolean some_inner_free = inner_free.size() > 0; - for (Enumeration e = inner_free.keys(); e.hasMoreElements(); ) { - String name = (String)e.nextElement(); + for (Enumeration e = inner_free.keys(); e.hasMoreElements();) { + String name = (String) e.nextElement(); SymInfo info = tbl.get(name); if (info == null) { - tbl.put(name,new SymInfo(FREE)); + tbl.put(name, new SymInfo(FREE)); continue; } int flags = info.flags; if (func) { // not func global and bound ? - if ((flags&NGLOBAL) == 0 && (flags&BOUND) != 0) { + if ((flags & NGLOBAL) == 0 && (flags & BOUND) != 0) { info.flags |= CELL; - if ((info.flags&PARAM) != 0) + if ((info.flags & PARAM) != 0) { jy_paramcells.addElement(name); + } cellvars.addElement(name); info.env_index = cell++; - if ((flags&PARAM) == 0) purecells.addElement(name); + if ((flags & PARAM) == 0) { + purecells.addElement(name); + } continue; } } else { @@ -169,9 +192,11 @@ public void cook(ScopeInfo up, int distance, CompilationContext ctxt) throws Exc String name = entry.getKey(); SymInfo info = entry.getValue(); int flags = info.flags; - if (nested && (flags&FREE) != 0) up.inner_free.put(name,PRESENT); - if ((flags&(GLOBAL|PARAM|CELL)) == 0) { - if ((flags&BOUND) != 0) { // ?? only func + if (nested && (flags & FREE) != 0) { + up.inner_free.put(name, PRESENT); + } + if ((flags & (GLOBAL | PARAM | CELL)) == 0) { + if ((flags & BOUND) != 0) { // ?? only func // System.err.println("local: "+name); names.addElement(name); info.locals_index = local++; @@ -179,7 +204,9 @@ public void cook(ScopeInfo up, int distance, CompilationContext ctxt) throws Exc } info.flags |= FREE; some_free = true; - if (nested) up.inner_free.put(name,PRESENT); + if (nested) { + up.inner_free.put(name, PRESENT); + } } } if ((jy_npurecell = purecells.size()) > 0) { @@ -195,9 +222,11 @@ public void cook(ScopeInfo up, int distance, CompilationContext ctxt) throws Exc // XXX - this doesn't catch all cases - may depend subtly // on how visiting NOW works with antlr compared to javacc if ((unqual_exec || from_import_star)) { - if(some_inner_free) dynastuff_trouble(true, ctxt); - else if(func_level > 1 && some_free) + if (some_inner_free) { + dynastuff_trouble(true, ctxt); + } else if (func_level > 1 && some_free) { dynastuff_trouble(false, ctxt); + } } } @@ -205,12 +234,10 @@ else if(func_level > 1 && some_free) private void dynastuff_trouble(boolean inner_free, CompilationContext ctxt) throws Exception { StringBuilder illegal = new StringBuilder(); if (unqual_exec && from_import_star) { - illegal.append("function '") - .append(scope_name) + illegal.append("function '").append(scope_name) .append("' uses import * and bare exec, which are illegal"); } else if (unqual_exec) { - illegal.append("unqualified exec is not allowed in function '") - .append(scope_name) + illegal.append("unqualified exec is not allowed in function '").append(scope_name) .append("'"); } else { illegal.append("import * is not allowed in function '").append(scope_name).append("'"); @@ -226,18 +253,18 @@ private void dynastuff_trouble(boolean inner_free, CompilationContext ctxt) thro public Vector freevars = new Vector(); /** - * setup the closure on this scope using the scope passed into cook as up as - * the containing scope + * setup the closure on this scope using the scope passed into cook as up as the containing + * scope */ public void setup_closure() { setup_closure(up); } /** - * setup the closure on this scope using the passed in scope. This is used - * by jythonc to setup its closures. + * setup the closure on this scope using the passed in scope. This is used by jythonc to setup + * its closures. */ - public void setup_closure(ScopeInfo up){ + public void setup_closure(ScopeInfo up) { int free = cell; // env = cell...,free... Map up_tbl = up.tbl; boolean nested = up.kind != TOPSCOPE; @@ -245,19 +272,19 @@ public void setup_closure(ScopeInfo up){ String name = entry.getKey(); SymInfo info = entry.getValue(); int flags = info.flags; - if ((flags&FREE) != 0) { + if ((flags & FREE) != 0) { SymInfo up_info = up_tbl.get(name); // ?? differs from CPython -- what is the intended behaviour? if (up_info != null) { int up_flags = up_info.flags; - if ((up_flags&(CELL|FREE)) != 0) { + if ((up_flags & (CELL | FREE)) != 0) { info.env_index = free++; freevars.addElement(name); continue; } // ! func global affect nested scopes - if (nested && (up_flags&NGLOBAL) != 0) { - info.flags = NGLOBAL|BOUND; + if (nested && (up_flags & NGLOBAL) != 0) { + info.flags = NGLOBAL | BOUND; continue; } } @@ -269,22 +296,19 @@ public void setup_closure(ScopeInfo up){ @Override public String toString() { - return "ScopeInfo[" + scope_name + " " + kind + "]@" + - System.identityHashCode(this); + return "ScopeInfo[" + scope_name + " " + kind + "]@" + System.identityHashCode(this); } public void defineAsGenerator(expr node) { generator = true; if (hasReturnWithValue) { - throw new ParseException("'return' with argument " + - "inside generator", node); + throw new ParseException("'return' with argument " + "inside generator", node); } } public void noteReturnValue(Return node) { if (generator) { - throw new ParseException("'return' with argument " + - "inside generator", node); + throw new ParseException("'return' with argument " + "inside generator", node); } hasReturnWithValue = true; } diff --git a/src/org/python/compiler/ScopesCompiler.java b/src/org/python/compiler/ScopesCompiler.java index ff51cdeb9..6dd474bdd 100644 --- a/src/org/python/compiler/ScopesCompiler.java +++ b/src/org/python/compiler/ScopesCompiler.java @@ -285,7 +285,7 @@ public Object visitName(Name node) throws Exception { @Override public Object visitListComp(ListComp node) throws Exception { - String tmp = "_[" + node.getLine() + "_" + node.getCharPositionInLine() + String tmp = "_[" + node.getLineno() + "_" + node.getCol_offset() + "]"; cur.addBound(tmp); traverse(node); @@ -328,7 +328,7 @@ private Object visitInternalGenerators(expr node, expr elt, java.util.List + * Since AbstractArray can support a clone method, this facilitates subclasses that want to + * implement clone (poor man's cloning). Subclasses can then do this: + * + *
    {@literal
          * public MyManagedArray(MyManagedArray toCopy) {
    -     * super(this);
    -     * this.baseArray = ()toCopy.copyArray();
    -     * this.someProp = toCopy.someProp;
    -     * 
    +     *     super(this);
    +     *     this.baseArray = () toCopy.copyArray();
    +     *     this.someProp = toCopy.someProp;
    +     *     
          * }
    -     * 

    + * * public Object clone() { - * return new MyManagedArray(this); + * return new MyManagedArray(this); * } - *

    + * } * * @param toCopy */ @@ -161,7 +161,7 @@ public void appendArray(Object ofArrayType) { *

    Note: This method does not set modCountIncr to * 1 even though java.util.ArrayList * would. - *

    + * *

    AbstractList subclasses should update their * modCount after calling this method. */ @@ -169,7 +169,7 @@ public void clear() { this.modCountIncr = 0; if (this.size != 0) { this.modCountIncr = 1; - clearRange(0, this.size); + clearRange(0, this.size); setSize(0); } @@ -400,43 +400,43 @@ public void replaceSubArray(Object array, int atIndex) { int arrayLen = Array.getLength(array); replaceSubArray(atIndex, Math.min(this.size, atIndex + arrayLen), array, 0, arrayLen); } - + /** * Replace a range of this array with another subarray. - * @param thisStart the start index (inclusive) of the subarray in this + * @param thisStart the start index (inclusive) of the subarray in this * array to be replaced - * @param thisStop the stop index (exclusive) of the subarray in this + * @param thisStop the stop index (exclusive) of the subarray in this * array to be replaced * @param srcArray the source array from which to copy * @param srcStart the start index (inclusive) of the replacement subarray * @param srcStop the stop index (exclusive) of the replacement subarray */ - public void replaceSubArray(int thisStart, int thisStop, Object srcArray, + public void replaceSubArray(int thisStart, int thisStop, Object srcArray, int srcStart, int srcStop) { - + this.modCountIncr = 0; if (!srcArray.getClass().isArray()) { throw new IllegalArgumentException("'array' must be an array type"); } - + int replacedLen = thisStop - thisStart; if (thisStart < 0 || replacedLen < 0 || thisStop > this.size) { String message = null; if (thisStart < 0) { message = "thisStart < 0 (thisStart = " + thisStart + ")"; } else if (replacedLen < 0) { - message = "thisStart > thistStop (thisStart = " + thisStart + + message = "thisStart > thistStop (thisStart = " + thisStart + ", thisStop = " + thisStop + ")"; } else if (thisStop > this.size) { - message = "thisStop > size (thisStop = " + thisStop + + message = "thisStop > size (thisStop = " + thisStop + ", size = " + this.size + ")"; } else { throw new InternalError("Incorrect validation logic"); } - + throw new ArrayIndexOutOfBoundsException(message); } - + int srcLen = Array.getLength(srcArray); int replacementLen = srcStop - srcStart; if (srcStart < 0 || replacementLen < 0 || srcStop > srcLen) { @@ -444,29 +444,29 @@ public void replaceSubArray(int thisStart, int thisStop, Object srcArray, if (srcStart < 0) { message = "srcStart < 0 (srcStart = " + srcStart +")"; } else if (replacementLen < 0) { - message = "srcStart > srcStop (srcStart = " + srcStart + + message = "srcStart > srcStop (srcStart = " + srcStart + ", srcStop = " + srcStop + ")"; } else if (srcStop > srcLen) { - message = "srcStop > srcArray length (srcStop = " + srcStop + + message = "srcStop > srcArray length (srcStop = " + srcStop + ", srcArray length = " +srcLen + ")"; } else { throw new InternalError("Incorrect validation logic"); } - + throw new IllegalArgumentException("start, stop and array must follow:\n\t" + "0 <= start <= stop <= array length\nBut found\n\t" + message); } - + int lengthChange = replacementLen - replacedLen; - + // Adjust array size if needed. if (lengthChange < 0) { remove(thisStop + lengthChange, thisStop); } else if (lengthChange > 0) { makeInsertSpace(thisStop, lengthChange); } - + try { this.modCountIncr = 1; System.arraycopy(srcArray, srcStart, getArray(), thisStart, replacementLen); @@ -475,7 +475,7 @@ public void replaceSubArray(int thisStart, int thisStop, Object srcArray, getArray().getClass().getName() + "\tsee java.lang.Class.getName()."); } } - + /** * Set the backing array. This method is used by the type-agnostic base * class code to set the array used for type-specific storage by the @@ -513,7 +513,7 @@ public void setSize(int count) { if (count > this.capacity) { ensureCapacity(count); } else if (count < this.size) { - clearRange(count, this.size); + clearRange(count, this.size); } this.size = count; } @@ -532,6 +532,7 @@ public int getSize() { * * @see java.lang.Object#toString() */ + @Override public String toString() { StringBuilder buf = new StringBuilder(); buf.append("["); @@ -543,7 +544,9 @@ public String toString() { for (int i = 0; i < n; i++) { buf.append(Array.get(base, i)).append(", "); } - if (n >= 0) buf.append(Array.get(base, n)); + if (n >= 0) { + buf.append(Array.get(base, n)); + } } else { Object[] objects = (Object[]) base; for (int i = 0; i < n; i++) { @@ -585,9 +588,9 @@ protected void trimToSize() { public int getModCountIncr() { return this.modCountIncr; } - + /** * @return an array of the given size for the type used by this abstract array. - */ + */ protected abstract Object createArray(int size); } diff --git a/src/org/python/core/AbstractDict.java b/src/org/python/core/AbstractDict.java index 84f6ec7c8..ad600cf20 100644 --- a/src/org/python/core/AbstractDict.java +++ b/src/org/python/core/AbstractDict.java @@ -6,6 +6,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; public abstract class AbstractDict extends PyObject { @@ -65,23 +66,80 @@ static Object tojava(Object val) { return val == null ? null : ((PyObject)val).__tojava__(Object.class); } - static class ValuesIter extends PyIterator { - - private final Iterator iterator; + /** + * Only valid for T=PyObject. + * Subclasses can use a different T, but then have to + * override __iternext__() accordingly. + */ + static abstract class AbstractDictIter extends PyIterator { - private final int size; + protected final Iterator iterator; + protected final int size; - public ValuesIter(Collection values) { + public AbstractDictIter(Collection values) { iterator = values.iterator(); size = values.size(); } + /** + * For use by subclasses. + */ + protected void check(int size) { + if (size != this.size) { + throw Py.RuntimeError("dictionary changed size during iteration"); + } + } + + /** + * Warning: This default implementation is only + * valid for T=PyObject. + */ + @Override + public PyObject __iternext__() { + if (!iterator.hasNext()) { + return null; + } + return (PyObject) iterator.next(); + } + } + + static class ValuesIter extends AbstractDictIter + { + public ValuesIter(Collection values) { + super(values); + } + } + + /** + * Only valid for T=PyObject. + * Subclasses can use a different T, but then have to + * override __iternext__() accordingly. + */ + static class KeysIter extends AbstractDictIter + { + public KeysIter(Collection keys) { + super(keys); + } + } + + /** + * Only valid for T=PyObject. + * Subclasses can use a different T, but then have to + * override __iternext__() accordingly. + */ + static class ItemsIter extends AbstractDictIter> { + + public ItemsIter(Set> items) { + super(items); + } + @Override public PyObject __iternext__() { if (!iterator.hasNext()) { return null; } - return iterator.next(); + Entry entry = iterator.next(); + return new PyTuple((PyObject) entry.getKey(), entry.getValue()); } } } diff --git a/src/org/python/core/AnnotationReader.java b/src/org/python/core/AnnotationReader.java index 9a5f0e4c9..1dfe9763c 100644 --- a/src/org/python/core/AnnotationReader.java +++ b/src/org/python/core/AnnotationReader.java @@ -36,7 +36,7 @@ public class AnnotationReader extends ClassVisitor { * @throws IOException - if the classfile is malformed. */ public AnnotationReader(byte[] data) throws IOException { - super(Opcodes.ASM5); + super(Opcodes.ASM7); ClassReader r; try { r = new ClassReader(data); @@ -52,7 +52,7 @@ public AnnotationVisitor visitAnnotation(String desc, boolean visible) { nextVisitIsVersion = desc.equals("Lorg/python/compiler/APIVersion;"); nextVisitIsMTime = desc.equals("Lorg/python/compiler/MTime;"); nextVisitIsFilename = desc.equals("Lorg/python/compiler/Filename;"); - return new AnnotationVisitor(Opcodes.ASM5) { + return new AnnotationVisitor(Opcodes.ASM7) { public void visit(String name, Object value) { if (nextVisitIsVersion) { diff --git a/src/org/python/core/BaseBytes.java b/src/org/python/core/BaseBytes.java index dd1495444..8889babff 100644 --- a/src/org/python/core/BaseBytes.java +++ b/src/org/python/core/BaseBytes.java @@ -9,12 +9,11 @@ import java.util.ListIterator; /** - * Base class for Jython bytearray (and bytes in due course) that provides - * most of the Java API, including Java {@link List} behaviour. Attempts to modify the contents - * through this API will throw a TypeError if the actual type of the object is not - * mutable. It is possible for a Java client to treat this class as a - * List<PyInteger>, obtaining equivalent functionality to the Python interface in a - * Java paradigm. + * Base class for Jython {@code bytearray} (and {@code bytes} in due course) that provides most of + * the Java API, including Java {@link List} behaviour. Attempts to modify the contents through this + * API will throw a {@code TypeError} if the actual type of the object is not mutable. It is + * possible for a Java client to treat this class as a {@code List}, obtaining equivalent + * functionality to the Python interface in a Java paradigm. *

    * Subclasses must define (from {@link PySequence}): *

      @@ -32,27 +31,26 @@ *

      * Many of the methods implemented here are inherited or thinly wrapped by {@link PyByteArray}, * which offers them as Java API, or exposes them as Python methods. These prototype Python methods - * mostly accept a {@link PyObject} as argument, where you might have expected a byte[] - * or BaseBytes, in order to accommodate the full range of types accepted by the Python - * equivalent: usually, any PyObject that implements {@link BufferProtocol}, providing - * a one-dimensional array of bytes, is an acceptable argument. In the documentation, the reader - * will often see the terms "byte array" or "object viewable as bytes" instead of - * BaseBytes when this broader scope is intended. + * mostly accept a {@link PyObject} as argument, where you might have expected a {@code byte[]} or + * {@code BaseBytes}, in order to accommodate the full range of types accepted by the Python + * equivalent: usually, any {@code PyObject} that implements {@link BufferProtocol}, providing a + * one-dimensional array of bytes, is an acceptable argument. In the documentation, the reader will + * often see the terms "byte array" or "object viewable as bytes" instead of {@code BaseBytes} when + * this broader scope is intended. *

      - * Where the methods return a BaseBytes, this is will normally be an instance of the - * class of the object on which the method was actually called. For example {@link #capitalize()}, - * defined in BaseBytes to return a BaseBytes, actually returns a {@link PyByteArray} - * when applied to a bytearray. Or it may be that the method returns a - * PyList of instances of the target type, for example {@link #rpartition(PyObject)}. - * This is achieved by the sub-class defining {@link #getslice(int, int, int)} and - * {@link #getBuilder(int)} to return instances of its own type. See the documentation of particular - * methods for more information. + * Where the methods return a {@code BaseBytes}, this is will normally be an instance of the class + * of the object on which the method was actually called. For example {@link #capitalize()}, defined + * in {@code BaseBytes} to return a BaseBytes, actually returns a {@link PyByteArray} when applied + * to a {@code bytearray}. Or it may be that the method returns a {@code PyList} of instances of the + * target type, for example {@link #rpartition(PyObject)}. This is achieved by the sub-class + * defining {@link #getslice(int, int, int)} and {@link #getResult(Builder)} to return instances of + * its own type. See the documentation of the particular methods for more information. */ @Untraversable public abstract class BaseBytes extends PySequence implements List { /** - * Constructs a zero-length BaseBytes of explicitly-specified sub-type. + * Constructs a zero-length {@code BaseBytes} of explicitly-specified sub-type. * * @param type explicit Jython type */ @@ -96,7 +94,7 @@ public BaseBytes(PyType type, int[] value) { * * @param type explicit Jython type * @param value source of characters - * @throws PyException if any value[i] > 255 + * @throws PyException {@code ValueError} if any {@code value[i] > 255} */ protected BaseBytes(PyType type, String value) throws PyException { super(type, null); @@ -117,10 +115,11 @@ protected BaseBytes(PyType type, String value) throws PyException { * @param storage byte array allocated by client * @param size number of bytes actually used * @param offset index of first byte used - * @throws IllegalArgumentException if the range [offset:offset+size] is not within the array - * bounds of storage or size<0. + * @throws IllegalArgumentException if the range {@code [offset:offset+size]} is not within the + * array bounds of storage or {@code size<0}. */ - protected void setStorage(byte[] storage, int size, int offset) throws IllegalArgumentException { + protected void setStorage(byte[] storage, int size, int offset) + throws IllegalArgumentException { if (size < 0 || offset < 0 || offset + size > storage.length) { throw new IllegalArgumentException(); } else { @@ -136,8 +135,8 @@ protected void setStorage(byte[] storage, int size, int offset) throws IllegalAr * * @param storage byte array allocated by client * @param size number of bytes actually used - * @throws IllegalArgumentException if the range [0:size] is not within the array bounds of - * storage. + * @throws IllegalArgumentException if the range {@code [0:size]} is not within the array bounds + * of storage. */ protected void setStorage(byte[] storage, int size) throws IllegalArgumentException { if (size < 0 || size > storage.length) { @@ -172,64 +171,49 @@ protected void setStorage(byte[] storage) { */ /** - * Helper for __new__ and __init__ and the Java API constructor from - * PyObject in subclasses. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from PyObject in + * subclasses. * - * @see org.python.core.ByteArray#bytearray___init__(PyObject[], String[]) - * @see org.python.core.ByteArray#ByteArray(PyObject) + * @see org.python.core.PyByteArray#bytearray___init__(PyObject[], String[]) + * @see org.python.core.PyByteArray#PyByteArray(PyObject) * @param arg primary argument from which value is taken - * @param encoding name of optional encoding (must be a string type) - * @param errors name of optional errors policy (must be a string type) */ protected void init(PyObject arg) { if (arg == null) { - /* - * bytearray() Construct a zero-length bytearray. - */ + // bytearray() Construct a zero-length bytearray. setStorage(emptyStorage); - } else if (arg instanceof PyString) { + } else if (arg instanceof PyString) { // or PyUnicode /* * bytearray(string) Construct from a text string by default encoding and error policy. * Cases where encoding and error policy are specified explicitly are dealt with * elsewhere. */ - init((PyString)arg, (String)null, (String)null); // Casts select right init() + init((PyString) arg, (String) null, (String) null); // Casts select right init() } else if (arg.isIndex()) { - /* - * bytearray(int) Construct a zero-initialised bytearray of the given length. - */ + // bytearray(int) Construct a zero-initialised bytearray of the given length. init(arg.asIndex(Py.OverflowError)); // overflow if too big to be Java int } else if (arg instanceof BaseBytes) { - /* - * bytearray copy of bytearray (or bytes) -- do efficiently - */ - init((BaseBytes)arg); + // bytearray copy of bytearray (or bytes) -- do efficiently + init((BaseBytes) arg); - } else if (arg instanceof BufferProtocol) { - /* - * bytearray copy of object supporting Jython implementation of PEP 3118 - */ - init((BufferProtocol)arg); + } else if (initFromBuffer(arg)) { + // arg supports Jython implementation of PEP 3118. (We're done.) } else { - /* - * The remaining alternative is an iterable returning (hopefully) right-sized ints. If - * it isn't one, we get an exception about not being iterable, or about the values. - */ + // The remaining alternative is an iterable returning (we hope) right-sized ints. init(arg.asIterable()); - } } /** - * Helper for __new__ and __init__ and the Java API constructor from a - * text string with the specified encoding in subclasses. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from a text + * string with the specified encoding in subclasses. * - * @see #bytearray___init__(PyObject[], String[]) + * @see PyByteArray#bytearray___init__(PyObject[], String[]) * @see PyByteArray#PyByteArray(PyString, String, String) * @param arg primary argument from which value is taken * @param encoding name of optional encoding (must be a string type) @@ -242,10 +226,10 @@ protected void init(PyString arg, PyObject encoding, PyObject errors) { } /** - * Helper for __new__ and __init__ and the Java API constructor from a - * text string with the specified encoding in subclasses. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from a text + * string with the specified encoding in subclasses. * - * @see #bytearray___init__(PyObject[], String[]) + * @see PyByteArray#bytearray___init__(PyObject[], String[]) * @see PyByteArray#PyByteArray(PyString, String, String) * @param arg primary argument from which value is taken * @param encoding name of optional encoding @@ -259,20 +243,21 @@ protected void init(PyString arg, String encoding, String errors) { } /** - * Helper for {@link #setslice(int, int, int, PyObject)}, for __new__ and - * __init__ and the Java API constructor from a text string with the specified - * encoding in subclasses. This method thinly wraps a call to the codecs module and deals with - * checking for PyUnicode (where the encoding argument is mandatory). + * Helper for {@link #setslice(int, int, int, PyObject)}, for {@code __new__} and + * {@code __init__} and the Java API constructor from a text string with the specified encoding + * in subclasses. This method thinly wraps a call to the codecs module and deals with checking + * for PyUnicode (where the encoding argument is mandatory). * - * @see #ByteArray(PyString, String, String) + * @see PyByteArray#PyByteArray(PyString, String, String) * @param arg primary argument from which value is taken * @param encoding name of optional encoding * @param errors name of optional errors policy * @return encoded string - * @throws PyException (TypeError) if the PyString is actually a {@link PyUnicode} - * and encoding is null + * @throws PyException {@code TypeError} if the {@code PyString} is actually a {@link PyUnicode} + * and encoding is {@code null} */ - protected static String encode(PyString arg, String encoding, String errors) throws PyException { + protected static String encode(PyString arg, String encoding, String errors) + throws PyException { // Jython encode emits a String (not byte[]) String encoded; @@ -298,7 +283,7 @@ protected static String encode(PyString arg, String encoding, String errors) thr * * @param start index in this byte array at which the first character code lands * @param value source of characters - * @throws PyException (ValueError) if any value[i] > 255 + * @throws PyException {@code ValueError} if any {@code value[i] > 255} */ protected void setBytes(int start, String value) throws PyException { int n = value.length(); @@ -314,7 +299,7 @@ protected void setBytes(int start, String value) throws PyException { * * @param start index in this byte array at which the first character code lands * @param value source of characters - * @throws PyException (ValueError) if any value[i] > 255 + * @throws PyException {@code ValueError} if any {@code value[i] > 255} */ protected void setBytes(int start, int step, String value) throws PyException { int n = value.length(); @@ -326,8 +311,8 @@ protected void setBytes(int start, int step, String value) throws PyException { } /** - * Helper for __new__ and __init__ and the Java API constructor from - * int in subclasses. Construct zero-filled byte array of specified size. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from int in + * subclasses. Construct zero-filled byte array of specified size. * * @param n size of zero-filled array */ @@ -339,14 +324,14 @@ protected void init(int n) { } /** - * Helper for __new__ and __init__ and the Java API constructor from - * objects supporting the Jython implementation of PEP 3118 (Buffer API) in subclasses. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from objects + * supporting the Jython implementation of PEP 3118 (Buffer API) in subclasses. * * @param value an object bearing the Buffer API and consistent with the slice assignment */ - protected void init(BufferProtocol value) throws PyException { + protected void init(BufferProtocol value) throws PyException, ClassCastException { // Get the buffer view - try (PyBuffer view = value.getBuffer(PyBUF.FULL_RO)) { + try (PyBuffer view = value.getBuffer(PyBUF.SIMPLE)) { // Create storage for the bytes and have the view drop them in newStorage(view.getLen()); view.copyTo(storage, offset); @@ -354,10 +339,27 @@ protected void init(BufferProtocol value) throws PyException { } /** - * Helper for __new__ and __init__ and the Java API constructor from - * bytearray or bytes in subclasses. + * Helper for {@code __new__} and {@code __init__} from objects that might support the + * Jython Buffer API. * - * @param source bytearray (or bytes) to copy + * @param value an object possibly bearing the Buffer API + * @return {@code true} iff {@code value} allows the {@code getBuffer} + */ + private boolean initFromBuffer(PyObject value) throws PyException { + if (value instanceof BufferProtocol) { + try { + init((BufferProtocol) value); + return true; + } catch (ClassCastException e) { /* fall through to false */ } + } + return false; + } + + /** + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from + * {@code bytearray} or {@code bytes} in subclasses. + * + * @param source {@code bytearray} (or {@code bytes}) to copy */ protected void init(BaseBytes source) { newStorage(source.size); @@ -365,8 +367,8 @@ protected void init(BaseBytes source) { } /** - * Helper for __new__ and __init__ and the Java API constructor from - * an arbitrary iterable Python type in subclasses. This will include generators and lists. + * Helper for {@code __new__} and {@code __init__} and the Java API constructor from an + * arbitrary iterable Python type in subclasses. This will include generators and lists. * * @param iter iterable source of values to enter in the array */ @@ -437,8 +439,9 @@ protected static class FragmentList extends LinkedList { * Load bytes into the container from the given iterable * * @param iter iterable source of values to enter into the container - * @throws PyException (TypeError) if any value not acceptable type - * @throws PyException (ValueError) if any value<0 or value>255 or string length!=1 + * @throws PyException {@code TypeError} if any value not acceptable type + * @throws PyException {@code ValueError} if any value<0 or value>255 or string + * length!=1 */ void loadFrom(Iterable iter) throws PyException { @@ -543,7 +546,7 @@ void emptyInto(byte[] target, int start, int step) { * Check that an index is within the range of the array, that is 0<=index<size. * * @param index to check - * @throws PyException (IndexError) if the index is outside the array bounds + * @throws PyException {@code IndexError} if the index is outside the array bounds */ protected final void indexCheck(int index) throws PyException { if (index < 0 || index >= size) { @@ -577,13 +580,13 @@ protected void newStorage(int needed) { * 0..255.) * * @param value to convert. - * @throws PyException (ValueError) if value<0 or value>255 + * @throws PyException {@code ValueError} if value<0 or value>255 */ protected static final byte byteCheck(int value) throws PyException { if (value < 0 || value > 255) { throw Py.ValueError("byte must be in range(0, 256)"); } - return (byte)value; + return (byte) value; } /** @@ -592,7 +595,7 @@ protected static final byte byteCheck(int value) throws PyException { * Python bytes run 0..255.) * * @param value to convert. - * @throws PyException (ValueError) if value<0 or value>255 + * @throws PyException {@code ValueError} if value<0 or value>255 */ protected static final byte byteCheck(PyInteger value) throws PyException { return byteCheck(value.asInt()); @@ -610,8 +613,8 @@ protected static final byte byteCheck(PyInteger value) throws PyException { *

    * * @param value to convert. - * @throws PyException (TypeError) if not acceptable type - * @throws PyException (ValueError) if value<0 or value>255 or string length!=1 + * @throws PyException {@code TypeError} if not acceptable type + * @throws PyException {@code ValueError} if value<0 or value>255 or string length!=1 */ protected static final byte byteCheck(PyObject value) throws PyException { if (value.isIndex()) { @@ -619,7 +622,7 @@ protected static final byte byteCheck(PyObject value) throws PyException { return byteCheck(value.asIndex()); } else if (value.getType() == PyString.TYPE) { // Exactly PyString (not PyUnicode) - String strValue = ((PyString)value).getString(); + String strValue = ((PyString) value).getString(); if (strValue.length() != 1) { throw Py.ValueError("string must be of size 1"); } @@ -630,12 +633,12 @@ protected static final byte byteCheck(PyObject value) throws PyException { } /** - * Return a buffer exported by the argument, or return null if it does not bear the + * Return a buffer exported by the argument, or return {@code null} if it does not bear the * buffer API. The caller is responsible for calling {@link PyBuffer#release()} on the buffer, - * if the return value is not null. + * if the return value is not {@code null}. * * @param b object to wrap - * @return byte-oriented view or null + * @return byte-oriented view or {@code null} */ protected static PyBuffer getView(PyObject b) { @@ -651,7 +654,7 @@ protected static PyBuffer getView(PyObject b) { return null; } else if (b instanceof BufferProtocol) { - return ((BufferProtocol)b).getBuffer(PyBUF.FULL_RO); + return ((BufferProtocol) b).getBuffer(PyBUF.FULL_RO); } else { return null; @@ -661,7 +664,7 @@ protected static PyBuffer getView(PyObject b) { /** * Return a buffer exported by the argument or raise an exception if it does not bear the buffer * API. The caller is responsible for calling {@link PyBuffer#release()} on the buffer. The - * return value is never null. + * return value is never {@code null}. * * @param b object to wrap * @return byte-oriented view @@ -707,9 +710,9 @@ protected PyInteger pyget(int index) { * * @param index to insert at * @param element to insert (by value) - * @throws PyException (IndexError) if the index is outside the array bounds - * @throws PyException (ValueError) if element<0 or element>255 - * @throws PyException (TypeError) if the subclass is immutable + * @throws PyException {@code IndexError} if the index is outside the array bounds + * @throws PyException {@code ValueError} if element<0 or element>255 + * @throws PyException {@code TypeError} if the subclass is immutable */ public void pyinsert(int index, PyObject element) { // This won't succeed: it just produces the right error. @@ -719,8 +722,8 @@ public void pyinsert(int index, PyObject element) { /** * Specialisation of {@link #getslice(int, int, int)} to contiguous slices (of step size 1) for - * brevity and efficiency. The default implementation is getslice(start, stop, 1) - * but it is worth overriding. + * brevity and efficiency. The default implementation is {@code getslice(start, stop, 1)} but it + * is worth overriding. * * @param start the position of the first element. * @param stop one more than the position of the last element. @@ -731,8 +734,8 @@ protected BaseBytes getslice(int start, int stop) { } /** - * Class defining the behaviour of bytearray with respect to slice assignment, - * etc., which differs from the default (list) behaviour in small ways. + * Class defining the behaviour of {@code bytearray} with respect to slice assignment, etc., + * which differs from the default (list) behaviour in small ways. */ private class IndexDelegate extends PySequence.DefaultIndexDelegate { @@ -770,11 +773,11 @@ public int __len__() { /** * Comparison function between a byte array and a buffer of bytes exported by some other object, - * such as a String, presented as a PyBuffer, returning 1, 0 or -1 as a>b, a==b, or + * such as a String, presented as a {@code PyBuffer}, returning 1, 0 or -1 as a>b, a==b, or * a<b respectively. The comparison is by value, using Python unsigned byte conventions, * left-to-right (low to high index). Zero bytes are significant, even at the end of the array: - * [65,66,67]<"ABC\u0000", for example and [] is less than every - * non-empty b, while []=="". + * {@code [65,66,67]<"ABC\u0000"}, for example and {@code []} is less than every non-empty b, + * while {@code []==""}. * * @param a left-hand array in the comparison * @param b right-hand wrapped object in the comparison @@ -848,8 +851,8 @@ private synchronized int basebytes_cmp(PyObject b) { /** * Fail-fast comparison function between byte array types and any other object, for when the - * test is only for equality. The "rich comparison" operators __eq__ and - * __ne__ are based on this. + * test is only for equality. The "rich comparison" operators {@code __eq__} and {@code __ne__} + * are based on this. * * @param b * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented @@ -884,10 +887,10 @@ private synchronized int basebytes_cmpeq(PyObject b) { /** * Implementation of __eq__ (equality) operator, capable of comparison with another byte array. - * Comparison with an invalid type returns null. + * Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___eq__(PyObject other) { int cmp = basebytes_cmpeq(other); @@ -902,10 +905,10 @@ final PyObject basebytes___eq__(PyObject other) { /** * Implementation of __ne__ (not equals) operator, capable of comparison with another byte - * array. Comparison with an invalid type returns null. + * array. Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___ne__(PyObject other) { int cmp = basebytes_cmpeq(other); @@ -920,10 +923,10 @@ final PyObject basebytes___ne__(PyObject other) { /** * Implementation of __lt__ (less than) operator, capable of comparison with another byte array. - * Comparison with an invalid type returns null. + * Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___lt__(PyObject other) { int cmp = basebytes_cmp(other); @@ -938,10 +941,10 @@ final PyObject basebytes___lt__(PyObject other) { /** * Implementation of __le__ (less than or equal to) operator, capable of comparison with another - * byte array. Comparison with an invalid type returns null. + * byte array. Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___le__(PyObject other) { int cmp = basebytes_cmp(other); @@ -956,10 +959,10 @@ final PyObject basebytes___le__(PyObject other) { /** * Implementation of __ge__ (greater than or equal to) operator, capable of comparison with - * another byte array. Comparison with an invalid type returns null. + * another byte array. Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___ge__(PyObject other) { int cmp = basebytes_cmp(other); @@ -974,10 +977,10 @@ final PyObject basebytes___ge__(PyObject other) { /** * Implementation of __gt__ (greater than) operator, capable of comparison with another byte - * array. Comparison with an invalid type returns null. + * array. Comparison with an invalid type returns {@code null}. * * @param other Python object to compare with - * @return Python boolean result or null if not implemented for the other type. + * @return Python boolean result or {@code null} if not implemented for the other type. */ final PyObject basebytes___gt__(PyObject other) { int cmp = basebytes_cmp(other); @@ -1015,17 +1018,17 @@ protected final synchronized boolean basebytes___contains__(PyObject target) { /** * Almost ready-to-expose implementation serving both Python - * startswith( prefix [, start [, end ]] ) and - * endswith( suffix [, start [, end ]] ). An extra boolean argument specifies which - * to implement on a given call, that is, whether the target is a suffix or prefix. The target - * may also be a tuple of targets. + * {@code startswith( prefix [, start [, end ]] )} and + * {@code endswith( suffix [, start [, end ]] )}. An extra boolean argument specifies which to + * implement on a given call, that is, whether the target is a suffix or prefix. The target may + * also be a tuple of targets. * * @param target prefix or suffix sequence to find (of a type viewable as a byte sequence) or a * tuple of those. * @param ostart of slice to search. * @param oend of slice to search. * @param endswith true if we are doing endswith, false if startswith. - * @return true if and only if this byte array ends with (one of) target. + * @return true if and only if this byte array ends with (one of) {@code target}. */ protected final synchronized boolean basebytes_starts_or_endswith(PyObject target, PyObject ostart, PyObject oend, boolean endswith) { @@ -1037,7 +1040,7 @@ protected final synchronized boolean basebytes_starts_or_endswith(PyObject targe if (target instanceof PyTuple) { // target is a tuple of suffixes/prefixes and only one need match - for (PyObject t : ((PyTuple)target).getList()) { + for (PyObject t : ((PyTuple) target).getList()) { if (match(t, index[0], index[3], endswith)) { return true; } @@ -1050,17 +1053,16 @@ protected final synchronized boolean basebytes_starts_or_endswith(PyObject targe } /** - * Test whether the slice [pos:pos+n] of this byte array matches the given target - * object (accessed as a {@link PyBuffer}) at one end or the orher. That is, if - * endswith==false test whether the bytes from index pos match all the - * bytes of the target; if endswith==false test whether the bytes up to index - * pos+n-1 match all the bytes of the target. By implication, the test returns - * false if the target is bigger than n. The caller guarantees that the slice - * [pos:pos+n] is within the byte array. + * Test whether the slice {@code [pos:pos+n]} of this byte array matches the given target object + * (accessed as a {@link PyBuffer}) at one end or the other. That is, if {@code endswith==false} + * test whether the bytes from index {@code pos} match all the bytes of the target; if + * {@code endswith==false} test whether the bytes up to index {@code pos+n-1} match all the + * bytes of the target. By implication, the test returns false if the target is bigger than n. + * The caller guarantees that the slice {@code [pos:pos+n]} is within the byte array. * * @param target pattern to match * @param pos at which to start the comparison - * @return true if and only if the slice [offset:] matches the given target + * @return true if and only if the slice {@code this[pos:pos+n]} matches the given target */ private boolean match(PyObject target, int pos, int n, boolean endswith) { @@ -1119,14 +1121,14 @@ public synchronized String asString() { char[] buf = new char[size]; int j = offset + size; for (int i = size; --i >= 0;) { - buf[i] = (char)(0xff & storage[--j]); + buf[i] = (char) (0xff & storage[--j]); } return new String(buf); } /** * Decode the byte array to a Unicode string according to the default encoding. The returned - * PyObject should be a PyUnicode, since the default codec is well-behaved. + * PyObject should be a {@code PyUnicode}, since the default codec is well-behaved. * * @return object containing the decoded characters */ @@ -1136,10 +1138,10 @@ public PyObject decode() { /** * Decode the byte array to a Unicode string according to the specified encoding and default - * error policy. The returned PyObject will usually be a PyUnicode, but in practice - * it is whatever the decode method of the codec decides. + * error policy. The returned PyObject will usually be a {@code PyUnicode}, but in practice it + * is whatever the {@code decode} method of the codec decides. * - * @param encoding the name of the codec (uses default codec if null) + * @param encoding the name of the codec (uses default codec if {@code null}) * @return object containing the decoded characters */ public PyObject decode(String encoding) { @@ -1148,18 +1150,18 @@ public PyObject decode(String encoding) { /** * Decode the byte array to a Unicode string according to the specified encoding and error - * policy. The returned PyObject will usually be a PyUnicode, but in practice it is - * whatever the decode method of the codec decides. + * policy. The returned PyObject will usually be a {@code PyUnicode}, but in practice it is + * whatever the {@code decode} method of the codec decides. * - * @param encoding the name of the codec (uses default codec if null) - * @param errors the name of the error policy (uses 'strict' if null) + * @param encoding the name of the codec (uses default codec if {@code null}) + * @param errors the name of the error policy (uses 'strict' if {@code null}) * @return object containing the decoded characters */ public PyObject decode(String encoding, String errors) { /* - * Provide a Python str input to the decode method of a codec, which in v2.7 - * expects a PyString. (In Python 3k the codecs decode from the bytes type, so - * we can pass this directly.) + * Provide a Python {@code str} input to the decode method of a codec, which in v2.7 expects + * a PyString. (In Python 3k the codecs decode from the {@code bytes} type, so we can pass + * this directly.) */ PyString this_ = new PyString(this.asString()); return codecs.decode(this_, encoding, errors); @@ -1170,7 +1172,7 @@ public PyObject decode(String encoding, String errors) { * * @param args Python argument list * @param keywords Assocaited keywords - * @return + * @return object containing the decoded characters */ protected final PyObject basebytes_decode(PyObject[] args, String[] keywords) { ArgParser ap = new ArgParser("decode", args, keywords, "encoding", "errors"); @@ -1180,8 +1182,8 @@ protected final PyObject basebytes_decode(PyObject[] args, String[] keywords) { } /** - * Convenience method to create a TypeError PyException with the message - * "can't concat {type} to {toType}" + * Convenience method to create a {@code TypeError} PyException with the message "can't concat + * {type} to {toType}" * * @param type * @param toType @@ -1258,11 +1260,11 @@ protected int index(byte b) { } /** - * This class implements the Boyer-Moore-Horspool Algorithm for find a pattern in text, applied - * to byte arrays. The BMH algorithm uses a table of bad-character skips derived from the - * pattern. The bad-character skips table tells us how far from the end of the pattern is a byte - * that might match the text byte currently aligned with the end of the pattern. For example, - * suppose the pattern ("panama") is at position 6: + * This class implements the Boyer-Moore-Horspool Algorithm for finding a pattern in text, + * applied to byte arrays. The BMH algorithm uses a table of bad-character skips derived from + * the pattern. The bad-character skips table tells us how far from the end of the pattern is a + * byte that might match the text byte currently aligned with the end of the pattern. For + * example, suppose the pattern ("panama") is at position 6: * *
          *                    1         2         3
    @@ -1272,7 +1274,7 @@ protected int index(byte b) {
          * 
    * * This puts the 'p' of 'map' against the last byte 'a' of the pattern. Rather than testing the - * pattern, we will look up 'p' in the skip table. There is an 'p' just 5 steps from the end of + * pattern, we will look up 'p' in the skip table. There is a 'p' just 5 steps from the end of * the pattern, so we will move the pattern 5 places to the right before trying to match it. * This allows us to move in large strides through the text. */ @@ -1290,13 +1292,12 @@ public Finder(PyBuffer pattern) { /** * Mask defining how many of the bits of each byte are used when looking up the skip, used - * like: skip = skipTable[MASK & currentByte]. + * like: {@code skip = skipTable[MASK & currentByte]}. */ private static final byte MASK = 0x1f; /** - * Table for looking up the skip, used like: - * skip = skipTable[MASK & currentByte]. + * Table for looking up the skip, used like: {@code skip = skipTable[MASK & currentByte]}. */ protected int[] skipTable = null; @@ -1322,8 +1323,8 @@ protected int[] calculateSkipTable() { } /** - * Set the text to be searched in successive calls to nextIndex(), where the - * text is the entire array text[]. + * Set the text to be searched in successive calls to {@code nextIndex()}, where the text is + * the entire array {@code text[]}. * * @param text to search */ @@ -1332,8 +1333,8 @@ public void setText(byte[] text) { } /** - * Set the text to be searched in successive calls to nextIndex(), where the - * text is the entire byte array text. + * Set the text to be searched in successive calls to {@code nextIndex()}, where the text is + * the entire byte array {@code text}. * * @param text to search */ @@ -1342,9 +1343,8 @@ public void setText(BaseBytes text) { } /** - * Set the text to be searched in successive calls to nextIndex(), where the - * text is effectively only the bytes text[start] to - * text[start+size-1] inclusive. + * Set the text to be searched in successive calls to {@code nextIndex()}, where the text is + * effectively only the bytes {@code text[start]} to {@code text[start+size-1]} inclusive. * * @param text to search * @param start first position to consider @@ -1374,8 +1374,8 @@ public void setText(byte[] text, int start, int size) { /** * Return the index in the text array where the preceding pattern match ends (one beyond the * last character matched), which may also be one beyond the effective end ofthe text. - * Between a call to setText() and the first call to nextIndex() return the - * start position. + * Between a call to setText() and the first call to {@code nextIndex()} return the start + * position. *

    * The following idiom may be used: * @@ -1394,8 +1394,8 @@ public int currIndex() { /** * Find the next index in the text array where the pattern starts. Successive calls to - * nextIndex() return the successive (non-overlapping) occurrences of the - * pattern in the text. + * {@code nextIndex()} return the successive (non-overlapping) occurrences of the pattern in + * the text. * * @return matching index or -1 if no (further) occurrences found */ @@ -1476,8 +1476,7 @@ public int count(byte[] text) { /** * Count the non-overlapping occurrences of the pattern in the text, where the text is - * effectively only the bytes text[start] to text[start+size-1] - * inclusive. + * effectively only the bytes {@code text[start]} to {@code text[start+size-1]} inclusive. * * @param text to search * @param start first position to consider @@ -1490,7 +1489,7 @@ public int count(byte[] text, int start, int size) { /** * Count the non-overlapping occurrences of the pattern in the text, where the text is - * effectively only the bytes text[start] to text[start+size-1]. + * effectively only the bytes {@code text[start]} to {@code text[start+size-1]}. * * @param text to search * @param start first position to consider @@ -1527,11 +1526,11 @@ public ReverseFinder(PyBuffer pattern) { /** * Mask defining how many of the bits of each byte are used when looking up the skip, used - * like: skip = skipTable[MASK & currentByte]. + * like: {@code skip = skipTable[MASK & currentByte]}. *

    - * Note that the way this is written at the moment, if MASK is different from - * super.MASK calculateSkipTable() and nextIndex() - * must both be overridden consistently to use the local definition. + * Note that the way this is written at the moment, if {@code MASK} is different from + * {@code super.MASK} {@code calculateSkipTable()} and {@code nextIndex()} must both be + * overridden consistently to use the local definition. */ private static final byte MASK = 0x1f; @@ -1569,7 +1568,7 @@ public int currIndex() { /** * Find the next index in the text array where the pattern starts, but working backwards. - * Successive calls to nextIndex() return the successive (non-overlapping) + * Successive calls to {@code nextIndex()} return the successive (non-overlapping) * occurrences of the pattern in the text. * * @return matching index or -1 if no (further) occurrences found @@ -1682,7 +1681,7 @@ public boolean contains(byte b) { * * @param b integer value of the byte * @return true iff b is in the set - * @throws ArrayIndexOutOfBoundsException if b>255 or b<0 + * @throws ArrayIndexOutOfBoundsException if b%gt;255 or b<0 */ public boolean contains(int b) { int word = b >> 6; @@ -1709,8 +1708,8 @@ protected final static int checkForEmptySeparator(PyBuffer separator) throws PyE } /** - * Return the index [0..size-1] of the leftmost byte not matching any in byteSet, - * or size if they are all strippable. + * Return the index [0..size-1] of the leftmost byte not matching any in {@code byteSet}, or + * {@code size} if they are all strippable. * * @param byteSet set of byte values to skip over * @return index of first unstrippable byte @@ -1730,8 +1729,8 @@ protected int lstripIndex(ByteSet byteSet) { } /** - * Return the index [0..size-1] of the leftmost non-whitespace byte, or size if - * they are all whitespace. + * Return the index [0..size-1] of the leftmost non-whitespace byte, or {@code size} if they are + * all whitespace. * * @return index of first non-whitespace byte */ @@ -1749,8 +1748,8 @@ protected int lstripIndex() { /** * Return the index [0..size-1] such that all bytes from here to the right match one in - * byteSet, that is, the index of the matching tail, or size if there - * is no matching tail byte. + * {@code byteSet}, that is, the index of the matching tail, or {@code size} if there is no + * matching tail byte. * * @param byteSet set of byte values to strip * @return index of strippable tail @@ -1770,7 +1769,7 @@ protected int rstripIndex(ByteSet byteSet) { /** * Return the index [0..size-1] such that all bytes from here to the right are whitespace, that - * is, the index of the whitespace tail, or size if there is no whitespace tail. + * is, the index of the whitespace tail, or {@code size} if there is no whitespace tail. * * @return index of strippable tail */ @@ -1786,10 +1785,10 @@ protected int rstripIndex() { } /** - * Ready-to-expose implementation of Python count( sub [, start [, end ]] ). Return - * the number of non-overlapping occurrences of sub in the range [start, end]. - * Optional arguments start and end (which may be null or - * Py.None ) are interpreted as in slice notation. + * Ready-to-expose implementation of Python {@code count( sub [, start [, end ]] )}. Return the + * number of non-overlapping occurrences of {@code sub} in the range [start, end]. Optional + * arguments {@code start} and {@code end} (which may be {@code null} or {@code Py.None}) are + * interpreted as in slice notation. * * @param sub bytes to find * @param ostart of slice to search @@ -1809,12 +1808,11 @@ final int basebytes_count(PyObject sub, PyObject ostart, PyObject oend) { } /** - * Ready-to-expose implementation of Python find( sub [, start [, end ]] ). Return - * the lowest index in the byte array where byte sequence sub is found, such that - * sub is contained in the slice [start:end]. Arguments - * start and end (which may be null or - * Py.None ) are interpreted as in slice notation. Return -1 if sub is - * not found. + * Ready-to-expose implementation of Python {@code find( sub [, start [, end ]] )}. Return the + * lowest index in the byte array where byte sequence {@code sub} is found, such that + * {@code sub} is contained in the slice {@code [start:end]}. Arguments {@code start} and + * {@code end} (which may be {@code null} or {@code Py.None} ) are interpreted as in slice + * notation. Return -1 if {@code sub} is not found. * * @param sub bytes to find * @param ostart of slice to search @@ -1829,10 +1827,10 @@ final int basebytes_find(PyObject sub, PyObject ostart, PyObject oend) { } /** - * Almost ready-to-expose implementation of Python class method fromhex(string). - * This assigns a value to the passed byte array object from a string of two-digit hexadecimal + * Almost ready-to-expose implementation of Python class method {@code fromhex(string)}. This + * assigns a value to the passed byte array object from a string of two-digit hexadecimal * numbers. Spaces (but not whitespace in general) are acceptable around the numbers, not - * within. Non-hexadecimal characters or un-paired hex digits raise a ValueError. + * within. Non-hexadecimal characters or un-paired hex digits raise a {@code ValueError}. * Example: * *

    @@ -1841,7 +1839,8 @@ final int basebytes_find(PyObject sub, PyObject ostart, PyObject oend) {
          *
          * @param result to receive the decoded values
          * @param hex specification of the bytes
    -     * @throws PyException (ValueError) if non-hex characters, or isolated ones, are encountered
    +     * @throws PyException {@code ValueError} if non-hex characters, or isolated ones, are
    +     *             encountered
          */
         static void basebytes_fromhex(BaseBytes result, String hex) throws PyException {
     
    @@ -1867,7 +1866,7 @@ static void basebytes_fromhex(BaseBytes result, String hex) throws PyException {
                         int value = hexDigit(c);
                         c = hex.charAt(i++); // Throw IndexOutOfBoundsException if no second digit
                         value = (value << 4) + hexDigit(c);
    -                    r[p++] = (byte)value;
    +                    r[p++] = (byte) value;
                     } catch (IllegalArgumentException e) {
                         throw Py.ValueError(String.format(fmt, i - 1));
                     } catch (IndexOutOfBoundsException e) {
    @@ -1903,7 +1902,7 @@ private static int hexDigit(char c) throws IllegalArgumentException {
         }
     
         /**
    -     * Almost ready-to-expose implementation of Python join(iterable).
    +     * Almost ready-to-expose implementation of Python {@code join(iterable)}.
          *
          * @param iter iterable of objects capable of being regarded as byte arrays
          * @return the byte array that is their join
    @@ -1922,8 +1921,8 @@ final synchronized PyByteArray basebytes_join(Iterable iter)
                     if (v == null) {
                         // Unsuitable object to be in this join
                         String fmt = "can only join an iterable of bytes (item %d has type '%.80s')";
    -                    throw Py.TypeError(String.format(fmt, iterList.size(), o.getType()
    -                            .fastGetName()));
    +                    throw Py.TypeError(
    +                            String.format(fmt, iterList.size(), o.getType().fastGetName()));
                     }
                     iterList.add(v);
                     totalSize += v.getLen();
    @@ -1941,7 +1940,7 @@ final synchronized PyByteArray basebytes_join(Iterable iter)
                 }
     
                 // Load the Views from the iterator into a new PyByteArray
    -            PyByteArray result = new PyByteArray((int)totalSize);
    +            PyByteArray result = new PyByteArray((int) totalSize);
                 int p = result.offset; // Copy-to pointer
                 first = true;
     
    @@ -1961,7 +1960,7 @@ final synchronized PyByteArray basebytes_join(Iterable iter)
                 return result;
     
             } finally {
    -            // All the buffers we acquired have to be realeased
    +            // All the buffers we acquired have to be released
                 for (PyBuffer v : iterList) {
                     v.release();
                 }
    @@ -1969,16 +1968,16 @@ final synchronized PyByteArray basebytes_join(Iterable iter)
         }
     
         /**
    -     * Implementation of Python partition(sep), returning a 3-tuple of byte arrays (of
    -     * the same type as this).
    +     * Implementation of Python {@code partition(sep)}, returning a 3-tuple of byte arrays (of the
    +     * same type as {@code this}).
          *
    -     * Split the string at the first occurrence of sep, and return a 3-tuple containing
    -     * the part before the separator, the separator itself, and the part after the separator. If the
    +     * Split the string at the first occurrence of {@code sep}, and return a 3-tuple containing the
    +     * part before the separator, the separator itself, and the part after the separator. If the
          * separator is not found, return a 3-tuple containing the string itself, followed by two empty
          * byte arrays.
          * 

    - * The elements of the PyTuple returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyTuple} returned by this method are instances of the same actual + * type as {@code this}. * * @param sep the separator on which to partition this byte array * @return a tuple of (head, separator, tail) @@ -1988,10 +1987,10 @@ public PyTuple partition(PyObject sep) { } /** - * Ready-to-expose implementation of Python partition(sep). + * Ready-to-expose implementation of Python {@code partition(sep)}. *

    - * The elements of the PyTuple returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyTuple} returned by this method are instances of the same actual + * type as {@code this}. * * @param sep the separator on which to partition this byte array * @return a tuple of (head, separator, tail) @@ -2018,11 +2017,11 @@ final synchronized PyTuple basebytes_partition(PyObject sep) { } /** - * Construct return value for implementation of Python partition(sep) or - * rpartition(sep), returns [0:p], [p:q], [q:] + * Construct return value for implementation of Python {@code partition(sep)} or + * {@code rpartition(sep)}, returns {@code [0:p], [p:q], [q:]} *

    - * The elements of the PyTuple returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyTuple} returned by this method are instances of the same actual + * type as {@code this}. * * @param p start of separator * @param q start of tail @@ -2036,12 +2035,11 @@ private PyTuple partition(int p, int q) { } /** - * Ready-to-expose implementation of Python rfind( sub [, start [, end ]] ). Return - * the highest index in the byte array where byte sequence sub is found, such that - * sub is contained in the slice [start:end]. Arguments - * start and end (which may be null or - * Py.None) are interpreted as in slice notation. Return -1 if sub is - * not found. + * Ready-to-expose implementation of Python {@code rfind( sub [, start [, end ]] )}. Return the + * highest index in the byte array where byte sequence {@code sub} is found, such that + * {@code sub} is contained in the slice {@code [start:end]}. Arguments {@code start} and + * {@code end} (which may be {@code null} or {@code Py.None}) are interpreted as in slice + * notation. Return -1 if {@code sub} is not found. * * @param sub bytes to find * @param ostart of slice to search @@ -2056,10 +2054,10 @@ final int basebytes_rfind(PyObject sub, PyObject ostart, PyObject oend) { } /** - * Common code for Python find( sub [, start [, end ]] ) and - * rfind( sub [, start [, end ]] ). Return the lowest or highest index in the byte - * array where byte sequence used to construct finder is found. The particular type - * (plain Finder or ReverseFinder) determines the direction. + * Common code for Python {@code find( sub [, start [, end ]] )} and + * {@code rfind( sub [, start [, end ]] )}. Return the lowest or highest index in the byte array + * where byte sequence used to construct {@code finder} is found. The particular type (plain + * {@code Finder} or {@code ReverseFinder}) determines the direction. * * @param finder for the bytes to find, sometime forwards, sometime backwards * @param ostart of slice to search @@ -2080,11 +2078,10 @@ private final int find(Finder finder, PyObject ostart, PyObject oend) { } /** - * An almost ready-to-expose implementation of Python - * replace( old, new [, count ] ), returning a PyByteArray with all - * occurrences of sequence oldB replaced by newB. If the optional - * argument count is given, only the first count occurrences are - * replaced. + * An almost ready-to-expose implementation of Python {@code replace( old, new [, count ] )}, + * returning a {@code PyByteArray} with all occurrences of sequence {@code oldB} replaced by + * {@code newB}. If the optional argument {@code count} is given, only the first {@code count} + * occurrences are replaced. * * @param oldB sequence to find * @param newB relacement sequence @@ -2187,7 +2184,7 @@ private PyByteArray replace_substring(PyBuffer from, PyBuffer to, int maxcount) byte[] r; // Build result here try { // Good to go. As we know the ultimate size, we can do all our allocation in one - r = new byte[(int)result_len]; + r = new byte[(int) result_len]; } catch (OutOfMemoryError e) { throw Py.OverflowError("replace bytes is too long"); } @@ -2250,11 +2247,11 @@ private PyByteArray replace_interleave(PyBuffer to, int maxcount) { int to_len = to.getLen(); // Calculate length of result and check for too big - long result_len = ((long)count) * to_len + size; + long result_len = ((long) count) * to_len + size; byte[] r; // Build result here try { // Good to go. As we know the ultimate size, we can do all our allocation in one - r = new byte[(int)result_len]; + r = new byte[(int) result_len]; } catch (OutOfMemoryError e) { throw Py.OverflowError("replace bytes is too long"); } @@ -2311,7 +2308,7 @@ private PyByteArray replace_delete_substring(PyBuffer from, int maxcount) { byte[] r; // Build result here try { // Good to go. As we know the ultimate size, we can do all our allocation in one - r = new byte[(int)result_len]; + r = new byte[(int) result_len]; } catch (OutOfMemoryError e) { throw Py.OverflowError("replace bytes is too long"); } @@ -2399,16 +2396,16 @@ private PyByteArray replace_substring_in_place(PyBuffer from, PyBuffer to, int m } /** - * Implementation of Python rpartition(sep), returning a 3-tuple of byte arrays (of - * the same type as this). + * Implementation of Python {@code rpartition(sep)}, returning a 3-tuple of byte arrays (of the + * same type as {@code this}). * - * Split the string at the rightmost occurrence of sep, and return a 3-tuple - * containing the part before the separator, the separator itself, and the part after the - * separator. If the separator is not found, return a 3-tuple containing two empty byte arrays, - * followed by the byte array itself. + * Split the string at the rightmost occurrence of {@code sep}, and return a 3-tuple containing + * the part before the separator, the separator itself, and the part after the separator. If the + * separator is not found, return a 3-tuple containing two empty byte arrays, followed by the + * byte array itself. *

    - * The elements of the PyTuple returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyTuple} returned by this method are instances of the same actual + * type as {@code this}. * * @param sep the separator on which to partition this byte array * @return a tuple of (head, separator, tail) @@ -2418,10 +2415,10 @@ public PyTuple rpartition(PyObject sep) { } /** - * Ready-to-expose implementation of Python rpartition(sep). + * Ready-to-expose implementation of Python {@code rpartition(sep)}. *

    - * The elements of the PyTuple returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyTuple} returned by this method are instances of the same actual + * type as {@code this}. * * @param sep the separator on which to partition this byte array * @return a tuple of (head, separator, tail) @@ -2448,11 +2445,11 @@ final synchronized PyTuple basebytes_rpartition(PyObject sep) { } /** - * Implementation of Python rsplit(), that returns a list of the words in the byte + * Implementation of Python {@code rsplit()}, that returns a list of the words in the byte * array, using whitespace as the delimiter. See {@link #rsplit(PyObject, int)}. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @return PyList of byte arrays that result from the split */ @@ -2461,14 +2458,14 @@ public PyList rsplit() { } /** - * Implementation of Python rsplit(sep), that returns a list of the words in the - * byte array, using sep as the delimiter. See {@link #rsplit(PyObject, int)} for - * the semantics of the separator. + * Implementation of Python {@code rsplit(sep)}, that returns a list of the words in the byte + * array, using {@code sep} as the delimiter. See {@link #rsplit(PyObject, int)} for the + * semantics of the separator. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @return PyList of byte arrays that result from the split */ public PyList rsplit(PyObject sep) { @@ -2476,27 +2473,27 @@ public PyList rsplit(PyObject sep) { } /** - * Implementation of Python rsplit(sep, maxsplit), that returns a list of the words - * in the byte array, using sep as the delimiter. If maxsplit is - * given, at most maxsplit splits are done (thus, the list will have at most - * maxsplit+1 elements). If maxsplit is not specified, then there is - * no limit on the number of splits (all possible splits are made). + * Implementation of Python {@code rsplit(sep, maxsplit)}, that returns a list of the words in + * the byte array, using {@code sep} as the delimiter. If {@code maxsplit} is given, at most + * {@code maxsplit} splits are done (thus, the list will have at most {@code maxsplit+1} + * elements). If {@code maxsplit} is not specified, then there is no limit on the number of + * splits (all possible splits are made). *

    - * The semantics of sep and maxcount are identical to those of - * split(sep, maxsplit) , except that splits are generated from the right (and - * pushed onto the front of the result list). The result is only different from that of - * split if maxcount limits the number of splits. For example, + * The semantics of {@code sep} and maxcount are identical to those of + * {@code split(sep, maxsplit)} , except that splits are generated from the right (and pushed + * onto the front of the result list). The result is only different from that of {@code split} + * if {@code maxcount} limits the number of splits. For example, *

      - *
    • bytearray(b' 1 2 3 ').rsplit() returns - * [bytearray(b'1'), bytearray(b'2'), bytearray(b'3')], and
    • - *
    • bytearray(b' 1 2 3 ').rsplit(None, 1) returns - * [bytearray(b' 1 2'), bytearray(b'3')]
    • . + *
    • {@code bytearray(b' 1 2 3 ').rsplit()} returns + * {@code [bytearray(b'1'), bytearray(b'2'), bytearray(b'3')]}, and
    • + *
    • {@code bytearray(b' 1 2 3 ').rsplit(None, 1)} returns + * {@code [bytearray(b' 1 2'), bytearray(b'3')]}.
    • *
    *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2505,14 +2502,14 @@ public PyList rsplit(PyObject sep, int maxsplit) { } /** - * Ready-to-expose implementation of Python rsplit(sep, maxsplit), that returns a - * list of the words in the byte array, using sep as the delimiter. Use the defines - * whitespace semantics if sep is null. + * Ready-to-expose implementation of Python {@code rsplit(sep, maxsplit)}, that returns a list + * of the words in the byte array, using {@code sep} as the delimiter. Use the defines + * whitespace semantics if {@code sep} is {@code null}. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2525,16 +2522,16 @@ final PyList basebytes_rsplit(PyObject sep, int maxsplit) { } /** - * Implementation of Python rsplit(sep, maxsplit), that returns a list of the words - * in the byte array, using sep (which is not null) as the delimiter. - * If maxsplit>=0, at most maxsplit splits are done (thus, the list - * will have at most maxsplit+1 elements). If maxsplit<0, then - * there is no limit on the number of splits (all possible splits are made). + * Implementation of Python {@code rsplit(sep, maxsplit)}, that returns a list of the words in + * the byte array, using {@code sep} (which is not {@code null}) as the delimiter. If + * {@code maxsplit>=0}, at most {@code maxsplit} splits are done (thus, the list will have at + * most {@code maxsplit+1} elements). If {@code maxsplit<0}, then there is no limit on the + * number of splits (all possible splits are made). *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2580,19 +2577,19 @@ final synchronized PyList basebytes_rsplit_explicit(PyObject sep, int maxsplit) } /** - * Implementation of Python rsplit(None, maxsplit), that returns a list of the - * words in the byte array, using whitespace as the delimiter. If maxsplit is - * given, at most maxsplit splits are done (thus, the list will have at most - * maxsplit+1 elements). If maxsplit is not specified, then there is no limit on - * the number of splits (all possible splits are made). + * Implementation of Python {@code rsplit(None, maxsplit)}, that returns a list of the words in + * the byte array, using whitespace as the delimiter. If {@code maxsplit} is given, at most + * {@code maxsplit} splits are done (thus, the list will have at most {@code maxsplit+1} + * elements). If maxsplit is not specified, then there is no limit on the number of splits (all + * possible splits are made). *

    * Runs of consecutive whitespace are regarded as a single separator, and the result will * contain no empty strings at the start or end if the string has leading or trailing * whitespace. Consequently, splitting an empty string or a string consisting of just whitespace - * with a None separator returns []. + * with a {@code None} separator returns []. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this/self. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this/self}. * * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split @@ -2641,11 +2638,11 @@ final synchronized PyList basebytes_rsplit_whitespace(int maxsplit) { } /** - * Implementation of Python split(), that returns a list of the words in the byte - * array, using whitespace as the delimiter. See {@link #split(PyObject, int)}. + * Implementation of Python {@code split()}, that returns a list of the words in the byte array, + * using whitespace as the delimiter. See {@link #split(PyObject, int)}. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @return PyList of byte arrays that result from the split */ @@ -2654,14 +2651,14 @@ public PyList split() { } /** - * Implementation of Python split(sep), that returns a list of the words in the - * byte array, using sep as the delimiter. See {@link #split(PyObject, int)} for - * the semantics of the separator. + * Implementation of Python {@code split(sep)}, that returns a list of the words in the byte + * array, using {@code sep} as the delimiter. See {@link #split(PyObject, int)} for the + * semantics of the separator. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @return PyList of byte arrays that result from the split */ public PyList split(PyObject sep) { @@ -2669,34 +2666,34 @@ public PyList split(PyObject sep) { } /** - * Implementation of Python split(sep, maxsplit), that returns a list of the words - * in the byte array, using sep as the delimiter. If maxsplit is - * given, at most maxsplit splits are done. (Thus, the list will have at most - * maxsplit+1 elements). If maxsplit is not specified, then there is - * no limit on the number of splits (all possible splits are made). + * Implementation of Python {@code split(sep, maxsplit)}, that returns a list of the words in + * the byte array, using {@code sep} as the delimiter. If {@code maxsplit} is given, at most + * {@code maxsplit} splits are done. (Thus, the list will have at most {@code maxsplit+1} + * elements). If {@code maxsplit} is not specified, then there is no limit on the number of + * splits (all possible splits are made). *

    - * If sep is given, consecutive delimiters are not grouped together and are deemed - * to delimit empty strings (for example, '1,,2'.split(',') returns - * ['1', '', '2']). The sep argument may consist of multiple - * characters (for example, '1<>2<>3'.split('<>') returns ['1', - * '2', '3']). Splitting an empty string with a specified separator ['']. + * If {@code sep} is given, consecutive delimiters are not grouped together and are deemed to + * delimit empty strings (for example, {@code '1,,2'.split(',')} returns + * {@code ['1', '', '2']}). The {@code sep} argument may consist of multiple characters (for + * example, {@code '1<>2<>3'.split('<>')} returns {@code ['1', '2', '3']}). Splitting an empty + * string with a specified separator {@code ['']}. *

    - * If sep is not specified or is None, a different splitting algorithm - * is applied: runs of consecutive whitespace are regarded as a single separator, and the result + * If {@code sep} is not specified or is {@code None}, a different splitting algorithm is + * applied: runs of consecutive whitespace are regarded as a single separator, and the result * will contain no empty strings at the start or end if the string has leading or trailing * whitespace. Consequently, splitting an empty string or a string consisting of just whitespace - * with a None separator returns []. For example, + * with a {@code None} separator returns {@code []}. For example, *

      - *
    • bytearray(b' 1 2 3 ').split() returns - * [bytearray(b'1'), bytearray(b'2'), bytearray(b'3')], and
    • - *
    • bytearray(b' 1 2 3 ').split(None, 1) returns - * [bytearray(b'1'), bytearray(b'2 3 ')].
    • + *
    • {@code bytearray(b' 1 2 3 ').split()} returns + * {@code [bytearray(b'1'), bytearray(b'2'), bytearray(b'3')]}, and
    • + *
    • {@code bytearray(b' 1 2 3 ').split(None, 1)} returns + * {@code [bytearray(b'1'), bytearray(b'2 3 ')]}.
    • *
    *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2705,14 +2702,14 @@ public PyList split(PyObject sep, int maxsplit) { } /** - * Ready-to-expose implementation of Python split(sep, maxsplit), that returns a - * list of the words in the byte array, using sep as the delimiter. Use the defines - * whitespace semantics if sep is null. + * Ready-to-expose implementation of Python {@code split(sep, maxsplit)}, that returns a list of + * the words in the byte array, using {@code sep} as the delimiter. Use the defines whitespace + * semantics if {@code sep} is {@code null}. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2725,16 +2722,16 @@ final PyList basebytes_split(PyObject sep, int maxsplit) { } /** - * Implementation of Python split(sep, maxsplit), that returns a list of the words - * in the byte array, using sep (which is not null) as the delimiter. - * If maxsplit>=0, at most maxsplit splits are done (thus, the list - * will have at most maxsplit+1 elements). If maxsplit<0, then - * there is no limit on the number of splits (all possible splits are made). + * Implementation of Python {@code split(sep, maxsplit)}, that returns a list of the words in + * the byte array, using {@code sep} (which is not {@code null}) as the delimiter. If + * {@code maxsplit>=0}, at most {@code maxsplit} splits are done (thus, the list will have at + * most {@code maxsplit+1} elements). If {@code maxsplit<0}, then there is no limit on the + * number of splits (all possible splits are made). *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * - * @param sep bytes, or object viewable as bytes, defining the separator + * @param sep {@code bytes}, or object viewable as bytes, defining the separator * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split */ @@ -2771,19 +2768,19 @@ final synchronized PyList basebytes_split_explicit(PyObject sep, int maxsplit) { } /** - * Implementation of Python split(None, maxsplit), that returns a list of the words - * in the byte array, using whitespace as the delimiter. If maxsplit is given, at - * most maxsplit splits are done (thus, the list will have at most maxsplit+1 - * elements). If maxsplit is not specified, then there is no limit on the number of - * splits (all possible splits are made). + * Implementation of Python {@code split(None, maxsplit)}, that returns a list of the words in + * the byte array, using whitespace as the delimiter. If {@code maxsplit} is given, at most + * maxsplit splits are done (thus, the list will have at most {@code maxsplit+1} elements). If + * {@code maxsplit} is not specified, then there is no limit on the number of splits (all + * possible splits are made). *

    * Runs of consecutive whitespace are regarded as a single separator, and the result will * contain no empty strings at the start or end if the string has leading or trailing * whitespace. Consequently, splitting an empty string or a string consisting of just whitespace - * with a None separator returns []. + * with a {@code None} separator returns []. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @param maxsplit maximum number of splits * @return PyList of byte arrays that result from the split @@ -2826,11 +2823,11 @@ final synchronized PyList basebytes_split_whitespace(int maxsplit) { } /** - * Implementation of Python splitlines(), returning a list of the lines in the byte + * Implementation of Python {@code splitlines()}, returning a list of the lines in the byte * array, breaking at line boundaries. Line breaks are not included in the resulting segments. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @return List of segments */ @@ -2839,12 +2836,12 @@ public PyList splitlines() { } /** - * Implementation of Python splitlines(keepends), returning a list of the lines in - * the string, breaking at line boundaries. Line breaks are not included in the resulting list - * unless keepends is true. + * Implementation of Python {@code splitlines(keepends)}, returning a list of the lines in the + * string, breaking at line boundaries. Line breaks are not included in the resulting list + * unless {@code keepends} is true. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @param keepends if true, include the end of line bytes(s) * @return PyList of segments @@ -2854,12 +2851,12 @@ public PyList splitlines(boolean keepends) { } /** - * Ready-to-expose implementation of Python splitlines(keepends), returning a list - * of the lines in the array, breaking at line boundaries. Line breaks are not included in the - * resulting list unless keepends is given and true. + * Ready-to-expose implementation of Python {@code splitlines(keepends)}, returning a list of + * the lines in the array, breaking at line boundaries. Line breaks are not included in the + * resulting list unless {@code keepends} is given and true. *

    - * The elements of the PyList returned by this method are instances of the same - * actual type as this. + * The elements of the {@code PyList} returned by this method are instances of the same actual + * type as {@code this}. * * @param keepends if true, include the end of line bytes(s) * @return List of segments @@ -2905,19 +2902,19 @@ protected final synchronized PyList basebytes_splitlines(boolean keepends) { // /** - * Helper to check the fill byte for {@link #rjust(String)}, {@link #ljust(String)} and - * {@link #center(String)}, which is required to be a single character string, treated as a - * byte. + * Helper to check the fill byte for {@link #basebytes_rjust(int, String)}, + * {@link #basebytes_ljust(int, String)} and {@link #basebytes_center(int, String)}, which is + * required to be a single character string, treated as a byte. * * @param function name - * @param fillchar or null - * @return + * @param fillchar or {@code null} + * @return the (checked) single fill byte */ protected static byte fillByteCheck(String function, String fillchar) { if (fillchar == null) { return ' '; } else if (fillchar.length() == 1) { - return (byte)fillchar.charAt(0); + return (byte) fillchar.charAt(0); } else { throw Py.TypeError(function + "() argument 2 must be char, not str"); } @@ -2927,8 +2924,8 @@ protected static byte fillByteCheck(String function, String fillchar) { * Helper function to construct the return value for {@link #rjust(String)}, * {@link #ljust(String)} and {@link #center(String)}. Clients calculate the left and right fill * values according to their nature, and ignoring the possibility that the desired - * width=left+size+right may be less than this.size. This method does - * all the work, and deals with that exceptional case by returning self[:]. + * {@code width=left+size+right} may be less than {@code this.size}. This method does all the + * work, and deals with that exceptional case by returning {@code self[:]}. * * @param pad byte to fill with * @param left padding requested @@ -2944,22 +2941,22 @@ private BaseBytes padHelper(byte pad, int left, int right) { } // Construct the result in a Builder of the desired width - Builder builder = getBuilder(left + size + right); + Builder builder = new Builder(left + size + right); builder.repeat(pad, left); builder.append(this); builder.repeat(pad, right); - return builder.getResult(); + return getResult(builder); } /** - * A ready-to-expose implementation of Python center(width [, fillchar]): return - * the bytes centered in an array of length width. Padding is done using the - * specified fillchar (default is a space). A copy of the original byte array is returned if - * width is less than this.size(). (Immutable subclasses may return - * exactly the original object.) + * A ready-to-expose implementation of Python {@code center(width [, fillchar])}: return the + * bytes centered in an array of length {@code width}. Padding is done using the specified + * fillchar (default is a space). A copy of the original byte array is returned if {@code width} + * is less than {@code this.size()}. (Immutable subclasses may return exactly the original + * object.) * * @param width desired - * @param fillchar one-byte String to fill with, or null implying space + * @param fillchar one-byte String to fill with, or {@code null} implying space * @return (possibly new) byte array containing the result */ final BaseBytes basebytes_center(int width, String fillchar) { @@ -2973,14 +2970,14 @@ final BaseBytes basebytes_center(int width, String fillchar) { } /** - * A ready-to-expose implementation of Python ljust(width [, fillchar]): return the - * bytes left-justified in an array of length width. Padding is done using the - * specified fillchar (default is a space). A copy of the original byte array is returned if - * width is less than this.size(). (Immutable subclasses may return - * exactly the original object.) + * A ready-to-expose implementation of Python {@code ljust(width [, fillchar])}: return the + * bytes left-justified in an array of length {@code width}. Padding is done using the specified + * fillchar (default is a space). A copy of the original byte array is returned if {@code width} + * is less than {@code this.size()}. (Immutable subclasses may return exactly the original + * object.) * * @param width desired - * @param fillchar one-byte String to fill with, or null implying space + * @param fillchar one-byte String to fill with, or {@code null} implying space * @return (possibly new) byte array containing the result */ final BaseBytes basebytes_ljust(int width, String fillchar) { @@ -2992,14 +2989,14 @@ final BaseBytes basebytes_ljust(int width, String fillchar) { } /** - * A ready-to-expose implementation of Python rjust(width [, fillchar]): return the - * bytes right-justified in an array of length width. Padding is done using the + * A ready-to-expose implementation of Python {@code rjust(width [, fillchar])}: return the + * bytes right-justified in an array of length {@code width}. Padding is done using the * specified fillchar (default is a space). A copy of the original byte array is returned if - * width is less than this.size(). (Immutable subclasses may return - * exactly the original object.) + * {@code width} is less than {@code this.size()}. (Immutable subclasses may return exactly the + * original object.) * * @param width desired - * @param fillchar one-byte String to fill with, or null implying space + * @param fillchar one-byte String to fill with, or {@code null} implying space * @return (possibly new) byte array containing the result */ final BaseBytes basebytes_rjust(int width, String fillchar) { @@ -3011,13 +3008,13 @@ final BaseBytes basebytes_rjust(int width, String fillchar) { } /** - * Ready-to-expose implementation of Python expandtabs([tabsize]): return a copy of - * the byte array where all tab characters are replaced by one or more spaces, depending on the + * Ready-to-expose implementation of Python {@code expandtabs([tabsize])}: return a copy of the + * byte array where all tab characters are replaced by one or more spaces, depending on the * current column and the given tab size. The column number is reset to zero after each newline * occurring in the array. This treats other non-printing characters or escape sequences as * regular characters. *

    - * The actual class of the returned object is determined by {@link #getBuilder(int)}. + * The actual class of the returned object is determined by {@link #getResult(Builder)}. * * @param tabsize number of character positions between tab stops * @return copy of this byte array with tabs expanded @@ -3025,8 +3022,8 @@ final BaseBytes basebytes_rjust(int width, String fillchar) { final BaseBytes basebytes_expandtabs(int tabsize) { // We could only work out the true size by doing the work twice, // so make a guess and let the Builder re-size if it's not enough. - int estimatedSize = size + size / 8; - Builder builder = getBuilder(estimatedSize); + long estimatedSize = (long) size + size / 8; + Builder builder = new Builder(estimatedSize); int carriagePosition = 0; int limit = offset + size; @@ -3036,7 +3033,7 @@ final BaseBytes basebytes_expandtabs(int tabsize) { if (c == '\t') { // Number of spaces is 1..tabsize int spaces = tabsize - carriagePosition % tabsize; - builder.repeat((byte)' ', spaces); + builder.repeat((byte) ' ', spaces); carriagePosition += spaces; } else { // Transfer the character, but if it is a line break, reset the carriage @@ -3045,13 +3042,13 @@ final BaseBytes basebytes_expandtabs(int tabsize) { } } - return builder.getResult(); + return getResult(builder); } /** - * Ready-to-expose implementation of Python zfill(width): return the numeric string - * left filled with zeros in a byte array of length width. A sign prefix is handled correctly if - * it is in the first byte. A copy of the original is returned if width is less than the current + * Ready-to-expose implementation of Python {@code zfill(width):} return the numeric string left + * filled with zeros in a byte array of length width. A sign prefix is handled correctly if it + * is in the first byte. A copy of the original is returned if width is less than the current * size of the array. * * @param width desired @@ -3060,7 +3057,7 @@ final BaseBytes basebytes_expandtabs(int tabsize) { final BaseBytes basebytes_zfill(int width) { // How many zeros will I need? int fill = width - size; - Builder builder = getBuilder((fill > 0) ? width : size); + Builder builder = new Builder((fill > 0) ? width : size); if (fill <= 0) { // width <= size so result is just a copy of this array @@ -3076,20 +3073,19 @@ final BaseBytes basebytes_zfill(int width) { } } // Now insert enough zeros - builder.repeat((byte)'0', fill); + builder.repeat((byte) '0', fill); // And finally the numeric part. Note possibility of no text eg. ''.zfill(6). if (size > p) { builder.append(this, p, size); } } - return builder.getResult(); + return getResult(builder); } // // Character class operations // - // Bit to twiddle (XOR) for lowercase letter to uppercase and vice-versa. private static final int SWAP_CASE = 0x20; @@ -3147,8 +3143,8 @@ static final boolean isspace(byte b) { } /** - * Java API equivalent of Python isalnum(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code isalnum()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all bytes in the array are code points for alphanumerics and there is at * least one byte, false otherwise. @@ -3158,7 +3154,7 @@ public boolean isalnum() { } /** - * Ready-to-expose implementation of Python isalnum(). + * Ready-to-expose implementation of Python {@code isalnum()}. * * @return true if all bytes in the array are code points for alphanumerics and there is at * least one byte, false otherwise. @@ -3180,8 +3176,8 @@ final boolean basebytes_isalnum() { } /** - * Java API equivalent of Python isalpha(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code isalpha()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all bytes in the array are alphabetic and there is at least one byte, false * otherwise @@ -3191,7 +3187,7 @@ public boolean isalpha() { } /** - * Ready-to-expose implementation of Python isalpha(). + * Ready-to-expose implementation of Python {@code isalpha()}. * * @return true if all bytes in the array are alphabetic and there is at least one byte, false * otherwise @@ -3213,8 +3209,8 @@ final boolean basebytes_isalpha() { } /** - * Java API equivalent of Python isdigit(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code isdigit()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all bytes in the array are code points for digits and there is at least one * byte, false otherwise. @@ -3224,7 +3220,7 @@ public boolean isdigit() { } /** - * Ready-to-expose implementation of Python isdigit(). + * Ready-to-expose implementation of Python {@code isdigit()}. * * @return true if all bytes in the array are code points for digits and there is at least one * byte, false otherwise. @@ -3246,8 +3242,8 @@ final boolean basebytes_isdigit() { } /** - * Java API equivalent of Python islower(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code islower()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all cased bytes in the array are code points for lowercase characters and * there is at least one cased byte, false otherwise. @@ -3257,7 +3253,7 @@ public boolean islower() { } /** - * Ready-to-expose implementation of Python islower(). + * Ready-to-expose implementation of Python {@code islower()}. * * @return true if all cased bytes in the array are code points for lowercase characters and * there is at least one cased byte, false otherwise. @@ -3295,8 +3291,8 @@ final boolean basebytes_islower() { } /** - * Java API equivalent of Python isspace(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code isspace()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all the bytes in the array are code points for whitespace characters and * there is at least one byte, false otherwise. @@ -3306,7 +3302,7 @@ public boolean isspace() { } /** - * Ready-to-expose implementation of Python isspace(). + * Ready-to-expose implementation of Python {@code isspace()}. * * @return true if all the bytes in the array are code points for whitespace characters and * there is at least one byte, false otherwise. @@ -3328,8 +3324,8 @@ final boolean basebytes_isspace() { } /** - * Java API equivalent of Python istitle(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code istitle()}. This method treats the bytes as US-ASCII + * code points. * * @return true if the string is a titlecased string and there is at least one cased byte, for * example uppercase characters may only follow uncased bytes and lowercase characters @@ -3340,7 +3336,7 @@ public boolean istitle() { } /** - * Ready-to-expose implementation of Python istitle(). + * Ready-to-expose implementation of Python {@code istitle()}. * * @return true if the string is a titlecased string and there is at least one cased byte, for * example uppercase characters may only follow uncased bytes and lowercase characters @@ -3354,7 +3350,7 @@ final boolean basebytes_istitle() { // 2 = in a word (hence have have seen cased character) for (int i = 0; i < size; i++) { - byte c = storage[offset+i]; + byte c = storage[offset + i]; if (isupper(c)) { if (state == 2) { // Violation: can't continue a word in upper case @@ -3380,8 +3376,8 @@ final boolean basebytes_istitle() { } /** - * Java API equivalent of Python isupper(). This method treats the bytes as - * US-ASCII code points. + * Java API equivalent of Python {@code isupper()}. This method treats the bytes as US-ASCII + * code points. * * @return true if all cased bytes in the array are code points for uppercase characters and * there is at least one cased byte, false otherwise. @@ -3391,7 +3387,7 @@ public boolean isupper() { } /** - * Ready-to-expose implementation of Python isupper(). + * Ready-to-expose implementation of Python {@code isupper()}. * * @return true if all cased bytes in the array are code points for uppercase characters and * there is at least one cased byte, false otherwise. @@ -3433,9 +3429,9 @@ final boolean basebytes_isupper() { // /** - * Java API equivalent of Python capitalize(). This method treats the bytes as - * US-ASCII code points. The BaseBytes returned by this method has the same actual - * type as this/self. + * Java API equivalent of Python {@code capitalize()}. This method treats the bytes as US-ASCII + * code points. The {@code BaseBytes} returned by this method has the same actual type as + * {@code this/self}. * * @return a copy of the array with its first character capitalized and the rest lowercased. */ @@ -3444,15 +3440,14 @@ public BaseBytes capitalize() { } /** - * Ready-to-expose implementation of Python capitalize(). The - * BaseBytes returned by this method has the same actual type as - * this/self. + * Ready-to-expose implementation of Python {@code capitalize()}. The {@code BaseBytes} returned + * by this method has the same actual type as {@code this/self}. * * @return a copy of the array with its first character capitalized and the rest lowercased. */ final BaseBytes basebytes_capitalize() { - Builder builder = getBuilder(size); + Builder builder = new Builder(size); if (size > 0) { // Treat first character @@ -3465,7 +3460,7 @@ final BaseBytes basebytes_capitalize() { // Treat the rest for (int i = 1; i < size; i++) { - c = storage[offset+i]; + c = storage[offset + i]; if (isupper(c)) { c ^= SWAP_CASE; // 'A' -> 'a', etc. } @@ -3474,13 +3469,13 @@ final BaseBytes basebytes_capitalize() { } } - return builder.getResult(); + return getResult(builder); } /** - * Java API equivalent of Python lower(). This method treats the bytes as US-ASCII - * code points. The BaseBytes returned by this method has the same actual type as - * this/self. + * Java API equivalent of Python {@code lower()}. This method treats the bytes as US-ASCII code + * points. The {@code BaseBytes} returned by this method has the same actual type as + * {@code this/self}. * * @return a copy of the array with all the cased characters converted to lowercase. */ @@ -3489,17 +3484,17 @@ public BaseBytes lower() { } /** - * Ready-to-expose implementation of Python lower(). The BaseBytes - * returned by this method has the same actual type as this/self. + * Ready-to-expose implementation of Python {@code lower()}. The {@code BaseBytes} returned by + * this method has the same actual type as {@code this/self}. * * @return a copy of the array with all the cased characters converted to lowercase. */ final BaseBytes basebytes_lower() { - Builder builder = getBuilder(size); + Builder builder = new Builder(size); for (int i = 0; i < size; i++) { - byte c = storage[offset+i]; + byte c = storage[offset + i]; if (isupper(c)) { c ^= SWAP_CASE; // 'A' -> 'a', etc. } @@ -3507,13 +3502,13 @@ final BaseBytes basebytes_lower() { builder.append(c); } - return builder.getResult(); + return getResult(builder); } /** - * Java API equivalent of Python swapcase(). This method treats the bytes as - * US-ASCII code points. The BaseBytes returned by this method has the same actual - * type as this/self. + * Java API equivalent of Python {@code swapcase()}. This method treats the bytes as US-ASCII + * code points. The {@code BaseBytes} returned by this method has the same actual type as + * {@code this/self}. * * @return a copy of the array with uppercase characters converted to lowercase and vice versa. */ @@ -3522,17 +3517,17 @@ public BaseBytes swapcase() { } /** - * Ready-to-expose implementation of Python swapcase(). The BaseBytes - * returned by this method has the same actual type as this/self. + * Ready-to-expose implementation of Python {@code swapcase()}. The {@code BaseBytes} returned + * by this method has the same actual type as {@code this/self}. * * @return a copy of the array with uppercase characters converted to lowercase and vice versa. */ final BaseBytes basebytes_swapcase() { - Builder builder = getBuilder(size); + Builder builder = new Builder(size); for (int i = 0; i < size; i++) { - byte c = storage[offset+i]; + byte c = storage[offset + i]; if (isalpha(c)) { c ^= SWAP_CASE; // 'a' -> 'A', 'A' -> 'a', etc. } @@ -3540,15 +3535,15 @@ final BaseBytes basebytes_swapcase() { builder.append(c); } - return builder.getResult(); + return getResult(builder); } /** - * Java API equivalent of Python title(). The algorithm uses a simple + * Java API equivalent of Python {@code title()}. The algorithm uses a simple * language-independent definition of a word as groups of consecutive letters. The definition * works in many contexts but it means that apostrophes in contractions and possessives form - * word boundaries, which may not be the desired result. The BaseBytes returned by - * this method has the same actual type as this/self. + * word boundaries, which may not be the desired result. The {@code BaseBytes} returned by this + * method has the same actual type as {@code this/self}. * * @return a titlecased version of the array where words start with an uppercase character and * the remaining characters are lowercase. @@ -3558,19 +3553,19 @@ public BaseBytes title() { } /** - * Ready-to-expose implementation of Python title(). The BaseBytes - * returned by this method has the same actual type as this/self. + * Ready-to-expose implementation of Python {@code title()}. The {@code BaseBytes} returned by + * this method has the same actual type as {@code this/self}. * * @return a titlecased version of the array where words start with an uppercase character and * the remaining characters are lowercase. */ final BaseBytes basebytes_title() { - Builder builder = getBuilder(size); + Builder builder = new Builder(size); boolean inWord = false; // We begin, not in a word (sequence of cased characters) for (int i = 0; i < size; i++) { - byte c = storage[offset+i]; + byte c = storage[offset + i]; if (!inWord) { // When we are not in a word ... @@ -3592,14 +3587,13 @@ final BaseBytes basebytes_title() { // Put the adjusted character in the output as a byte builder.append(c); } - return builder.getResult(); + return getResult(builder); } /** - * Java API equivalent of Python upper(). Note that - * x.upper().isupper() might be false if the array contains uncased - * characters. The BaseBytes returned by this method has the same actual type as - * this/self. + * Java API equivalent of Python {@code upper()}. Note that {@code x.upper().isupper()} might be + * {@code false} if the array contains uncased characters. The {@code BaseBytes} returned by + * this method has the same actual type as {@code this/self}. * * @return a copy of the array with all the cased characters converted to uppercase. */ @@ -3608,17 +3602,17 @@ public BaseBytes upper() { } /** - * Ready-to-expose implementation of Python upper(). The BaseBytes - * returned by this method has the same actual type as this/self. + * Ready-to-expose implementation of Python {@code upper()}. The {@code BaseBytes} returned by + * this method has the same actual type as {@code this/self}. * * @return a copy of the array with all the cased characters converted to uppercase. */ final BaseBytes basebytes_upper() { - Builder builder = getBuilder(size); + Builder builder = new Builder(size); for (int i = 0; i < size; i++) { - byte c = storage[offset+i]; + byte c = storage[offset + i]; if (islower(c)) { c ^= SWAP_CASE; // 'a' -> 'A' etc. } @@ -3626,7 +3620,7 @@ final BaseBytes basebytes_upper() { builder.append(c); } - return builder.getResult(); + return getResult(builder); } /* @@ -3652,48 +3646,13 @@ private final synchronized byte byteAt(int index) { * * @param index of value in byte array * @return the integer value at the index - * @throws PyException (IndexError) if the index is outside the array bounds + * @throws PyException {@code IndexError} if the index is outside the array bounds */ public synchronized int intAt(int index) throws PyException { indexCheck(index); return 0xff & byteAt(index); } - /** - * Helper to implement {@link #repeat(int)}. Use something like: - * - *

    -     * @Override
    -     * protected PyByteArray repeat(int count) {
    -     *     PyByteArray ret = new PyByteArray();
    -     *     ret.setStorage(repeatImpl(count));
    -     *     return ret;
    -     * }
    -     * 
    - * - * @param count the number of times to repeat this. - * @return this byte array repeated count times. - */ - protected synchronized byte[] repeatImpl(int count) { - if (count <= 0) { - return emptyStorage; - } else { - // Allocate new storage, in a guarded way - long newSize = ((long)count) * size; - byte[] dst; - try { - dst = new byte[(int)newSize]; - } catch (OutOfMemoryError e) { - throw Py.MemoryError(e.getMessage()); - } - // Now fill with the repetitions needed - for (int i = 0, p = 0; i < count; i++, p += size) { - System.arraycopy(storage, offset, dst, p, size); - } - return dst; - } - } - // // str() and repr() have different behaviour (despite PEP 3137) // @@ -3710,10 +3669,10 @@ private static final void appendHexEscape(StringBuilder buf, int c) { } /** - * Almost ready-to-expose Python __repr__(), based on treating the bytes as point - * codes. The value added by this method is conversion of non-printing code points to - * hexadecimal escapes in printable ASCII, and bracketed by the given before and after strings. - * These are used to get the required presentation: + * Almost ready-to-expose Python {@code __repr__()}, based on treating the bytes as point codes. + * The value added by this method is conversion of non-printing code points to hexadecimal + * escapes in printable ASCII, and bracketed by the given before and after strings. These are + * used to get the required presentation: * *
          * bytearray(b'Hello world!')
    @@ -3723,7 +3682,7 @@ private static final void appendHexEscape(StringBuilder buf, int c) {
          *
          * @param before String to insert before the quoted text
          * @param after String to insert after the quoted text
    -     * @return string representation: before + "'" + String(this) + "'" + after
    +     * @return string representation: {@code before + "'" + String(this) + "'" + after}
          */
         final synchronized String basebytes_repr(String before, String after) {
     
    @@ -3750,7 +3709,7 @@ final synchronized String basebytes_repr(String before, String after) {
                     if (c == '\\' || c == '\'') {    // Special cases
                         buf.append('\\');
                     }
    -                buf.append((char)c);
    +                buf.append((char) c);
                 } else if (c == '\t') { // Special cases in the low 32
                     buf.append("\\t");
                 } else if (c == '\n') {
    @@ -3796,9 +3755,9 @@ public int size() {
              * Replaces the element at the specified position in this list with the specified element.
              *
              * @see java.util.AbstractList#set(int, java.lang.Object)
    -         * @throws PyException (TypeError) if actual class is immutable
    -         * @throws PyException (IndexError) if the index is outside the array bounds
    -         * @throws PyException (ValueError) if element<0 or element>255
    +         * @throws PyException {@code TypeError} if actual class is immutable
    +         * @throws PyException {@code IndexError} if the index is outside the array bounds
    +         * @throws PyException {@code ValueError} if element<0 or element>255
              */
             @Override
             public PyInteger set(int index, PyInteger element) throws PyException {
    @@ -3814,9 +3773,9 @@ public PyInteger set(int index, PyInteger element) throws PyException {
              * currently at that position and any subsequent elements to the right.
              *
              * @see java.util.AbstractList#add(int, java.lang.Object)
    -         * @throws PyException (IndexError) if the index is outside the array bounds
    -         * @throws PyException (ValueError) if element<0 or element>255
    -         * @throws PyException (TypeError) if the owning concrete subclass is immutable
    +         * @throws PyException {@code IndexError} if the index is outside the array bounds
    +         * @throws PyException {@code ValueError} if element<0 or element>255
    +         * @throws PyException {@code TypeError} if the owning concrete subclass is immutable
              */
             @Override
             public void add(int index, PyInteger element) throws PyException {
    @@ -3831,7 +3790,7 @@ public void add(int index, PyInteger element) throws PyException {
              * removed from the list.
              *
              * @see java.util.AbstractList#remove(int)
    -         * @throws PyException (IndexError) if the index is outside the array bounds
    +         * @throws PyException {@code IndexError} if the index is outside the array bounds
              */
             @Override
             public PyInteger remove(int index) {
    @@ -3844,11 +3803,11 @@ public PyInteger remove(int index) {
         };
     
         /**
    -     * Number of bytes in bytearray (or bytes) object.
    +     * Number of bytes in {@code bytearray} (or {@code bytes}) object.
          *
          * @see java.util.List#size()
          * @return Number of bytes in byte array.
    -     * */
    +     */
         @Override
         public int size() {
             return size;
    @@ -3960,17 +3919,15 @@ public void clear() {
         }
     
         /**
    -     * Test for the equality of (the value of) this byte array to the object other. In
    -     * the case where other is a PyObject, the comparison used is the
    -     * standard Python == operation through PyObject. When
    -     * other is not a PyObject, this object acts as a
    -     * List<PyInteger>.
    +     * Test for the equality of (the value of) this byte array to the object {@code other}. In the
    +     * case where {@code other} is a {@code PyObject}, the comparison used is the standard Python
    +     * {@code ==} operation through {@code PyObject}. When {@code other} is not a {@code PyObject},
    +     * this object acts as a {@code List}.
          *
          * @see java.util.List#equals(java.lang.Object)
          *
          * @param other object to compare this byte array to
    -     * @return true if and only if this byte array is equal (in value) to
    -     *         other
    +     * @return {@code true} if and only if this byte array is equal (in value) to {@code other}
          */
         @Override
         public boolean equals(Object other) {
    @@ -4070,55 +4027,50 @@ public List subList(int fromIndex, int toIndex) {
          */
     
         /**
    -     * A Builder holds a buffer of bytes to which new bytes may be appended while
    +     * Every sub-class of BaseBytes overrides this method to access a {@code Builder} and return
    +     * that class' particular type, possibly without copying. Although the instance of which this is
    +     * a method is not used, the class of that instance determines which overridden implementation
    +     * is chosen, and hence both the action and the return type.
    +     *
    +     * @param b containing the result
    +     * @return a new object of the correct sub-class
    +     */
    +    protected abstract BaseBytes getResult(Builder b);
    +
    +    /**
    +     * A {@code Builder} holds a buffer of bytes to which new bytes may be appended while
          * constructing the value of byte array, even when the type ultimately constructed is immutable.
          * The value it builds may be transferred (normally without copying) to a new instance of the
          * type being built.
    -     * 

    - * Builder is an abstract class. The each sub-class of BaseBytes may - * define its own concrete implementation in which {@link Builder#getResult()} returns an object - * of its own type, taking its value from the Builder contents using - * {@link #getStorage()} and {@link #getSize()}. Methods in BaseBytes obtain a - * Builder by calling the abstract method {@link BaseBytes#getBuilder(int)}, which - * the sub-class also defines, to return an isnstance of its characteristic Builder - * sub-class. The subclass that uses a method from BaseBytes returning a - * BaseBytes has to cast a returned from a BaseBytes method to its proper type. - * which it can do without error, since it was responsible for its actual type. - *

    - * Implementation note: This can be done in a type-safe way but, in the present design, - * only by making BaseBytes parameterised class. - * */ - protected static abstract class Builder /* */{ - - /** - * Return an object of type B extends BaseBytes whose content is what we built. - */ - abstract BaseBytes getResult(); + protected static class Builder { // Internal state private byte[] storage = emptyStorage; private int size = 0; /** - * Construct a builder with specified initial capacity. + * Construct a builder with specified initial capacity. The use of a {@code long} argument + * allows the caller to delegate overflow checks to this constructor in certain cases. One + * cannot allocate more bytes than the JVM-allows for an array. * * @param capacity */ - Builder(int capacity) { + Builder(long capacity) { makeRoomFor(capacity); } /** - * Get an array of bytes containing the accumulated value, and clear the existing contents - * of the Builder. {@link #getCount()} returns the number of valid bytes in this array, - * which may be longer than the valid data. + * Destructively get the array of bytes containing the accumulated value, leaving the + * Builder empty. The array may be longer than the valid data if {@link #makeRoomFor(long)} + * chose so. {@link #getSize()}, continues to return the number of valid bytes in the array + * last returned, until an append next occurs. This ensures the idiom + * {@code func(getStorage(), getSize())} works as expected. *

    * It is intended the client call this method only once to get the result of a series of - * append operations. A second call to {@link #getCount()}, before any further appending, + * append operations. A second call to {@link #getStorage()}, before any further appending, * returns a zero-length array. This is to ensure that the same array is not given out - * twice. However, {@link #getCount()} continues to return the number bytes accumulated - * until an append next occurs. + * twice. * * @return an array containing the accumulated result */ @@ -4129,8 +4081,8 @@ byte[] getStorage() { } /** - * Number of bytes accumulated. In conjunctin with {@link #getStorage()}, this provides the - * result. Unlike {@link #getStorage()}, it does not affect the contents. + * Number of bytes accumulated. In conjunction with {@link #getStorage()}, this provides the + * result. Unlike {@link #getStorage()}, it does not affect the contents of the builder. * * @return number of bytes accumulated */ @@ -4149,7 +4101,7 @@ void append(byte b) { } /** - * Append a number of repeats of a single byte to the value, fo example in padding. + * Append a number of repeats of a single byte to the value, for example in padding. * * @param b byte to repeat * @param n number of repeats (none if n<=0) @@ -4157,7 +4109,7 @@ void append(byte b) { void repeat(byte b, int n) { if (n > 0) { makeRoomFor(n); - while (n-- > 0) { + while (--n >= 0) { storage[size++] = b; } } @@ -4172,18 +4124,45 @@ void append(BaseBytes b) { append(b, 0, b.size); } + /** + * Repeat the contents of the given byte array. + * + * @param b + */ + void repeat(BaseBytes b, int n) { + repeat(b, 0, b.size, n); + } + /** * Append the contents of a slice of the given byte array. * * @param b * @param start index of first byte copied - * @param end index of fisrt byte not copied + * @param end index of first byte not copied */ void append(BaseBytes b, int start, int end) { - int n = end - start; - makeRoomFor(n); - System.arraycopy(b.storage, b.offset + start, storage, size, n); - size += n; + int len = end - start; + makeRoomFor(len); + System.arraycopy(b.storage, b.offset + start, storage, size, len); + size += len; + } + + /** + * Repeat the contents of a slice of the given byte array. + * + * @param b + * @param start index of first byte copied + * @param end index of first byte not copied + * @param n number of repetitions + */ + void repeat(BaseBytes b, int start, int end, int n) { + int len = end - start; + makeRoomFor(len * (long) n); + start += b.offset; + while (--n >= 0) { + System.arraycopy(b.storage, start, storage, size, len); + size += len; + } } /** @@ -4198,34 +4177,43 @@ void append(PyBuffer v) { size += n; } - // Ensure there is enough free space for n bytes (or allocate some) - void makeRoomFor(int n) throws PyException { - int needed = size + n; + /** + * Ensure there is room for an additional {@code n} bytes, if necessary allocating a new + * {@code byte[]} and copying the contents. Trap and convert to {@code PyException} any + * overflow. + * + * @param n additional capacity requested ({@code long} so we can recognise overflow). + * @throws PyException {@code OverflowError} when {@code sys.maxsize} is exceeded. + * @throws PyException {@code MemoryError} when free heap or JVM limitation is exceeded. + */ + final void makeRoomFor(long n) throws PyException { + long needed = size + n; if (needed > storage.length) { - try { - if (storage == emptyStorage) { - /* - * After getStorage(): size deliberately retains its prior value, even - * though storage is set to emptyStorage. However, the first (non-empty) - * append() operation after that lands us here, because storage.length==0. - */ - size = 0; - if (n > 0) { - // When previously empty (incluing the constructor) allocate exactly n. - storage = new byte[n]; + if (size > 0 && storage == emptyStorage) { + // Special case where append comes after a getStorage(). + size = 0; + needed = n; + } + // Guardedly allocate the needed amount (or a rounded-up amount) + if (needed > PySystemState.maxsize) { + throw Py.OverflowError("max bytes len is " + PySystemState.maxsize); + } else if (needed <= 0) { + storage = emptyStorage; + } else { + try { + if (size == 0) { + // Just a new array + storage = new byte[(int) needed]; + } else { + // New array preserving existing contents + byte[] existing = storage; + storage = new byte[roundUp((int) needed)]; + System.arraycopy(existing, 0, storage, 0, size); } - } else { - // We are expanding an existing allocation: be imaginative - byte[] old = storage; - storage = new byte[roundUp(needed)]; - System.arraycopy(old, 0, storage, 0, size); + } catch (OutOfMemoryError e) { + // Exceeded the available heap or the limits of this JVM. + throw Py.MemoryError(e.getMessage()); } - } catch (OutOfMemoryError e) { - /* - * MemoryError is right for most clients. Some (e.g. bytearray.replace()) should - * convert it to an overflow, with a customised message. - */ - throw Py.MemoryError(e.getMessage()); } } } @@ -4233,11 +4221,11 @@ void makeRoomFor(int n) throws PyException { /** * Choose a size appropriate to store the given number of bytes, with some room for growth, when - * allocating storage for mutable types or Builder. We'll be more generous than - * CPython for small array sizes to avoid needless reallocation. + * allocating storage for mutable types or {@code Builder}. We'll be more generous than CPython + * for small array sizes to avoid needless reallocation. * * @param size of storage actually needed - * @return n >= size a recommended storage array size + * @return n ≥ size a recommended storage array size */ protected static final int roundUp(int size) { /* @@ -4257,16 +4245,4 @@ protected static final int roundUp(int size) { return 0; } } - - /** - * Every sub-class of BaseBytes overrides this method to return a Builder<B> - * where B is (normally) that class's particular type, and it extends - * Builder<B> so that {@link Builder#getResult()} produces an instance of - * B from the contents. - * - * @param capacity of the Builder<B> returned - * @return a Builder<B> for the correct sub-class - */ - protected abstract Builder/* */getBuilder(int capacity); - } diff --git a/src/org/python/core/BaseSet.java b/src/org/python/core/BaseSet.java index 55fbeb0b8..1c603a2d1 100644 --- a/src/org/python/core/BaseSet.java +++ b/src/org/python/core/BaseSet.java @@ -31,7 +31,7 @@ protected void _update(PyObject data) { protected void _update(PyObject [] args) { _update(_set, args); } - + /** * Update the underlying set with the contents of the iterable. */ @@ -64,12 +64,13 @@ protected static Set _update(Set set, PyObject[] data) { } /** - * The union of this with other.


    (I.e. all elements + * The union of this with other.

    (I.e. all elements * that are in either set) * * @param other A BaseSet instance. * @return The union of the two sets as a new set. */ + @Override public PyObject __or__(PyObject other) { return baseset___or__(other); } @@ -83,13 +84,14 @@ final PyObject baseset___or__(PyObject other) { /** * The intersection of the this with other. - *

    - *
    + *

    + * * (I.e. all elements that are in both sets) * * @param other A BaseSet instance. * @return The intersection of the two sets as a new set. */ + @Override public PyObject __and__(PyObject other) { return baseset___and__(other); } @@ -103,13 +105,14 @@ final PyObject baseset___and__(PyObject other) { /** * The difference of the this with other. - *

    - *
    + *

    + * * (I.e. all elements that are in this set and not in the other) * * @param other A BaseSet instance. * @return The difference of the two sets as a new set. */ + @Override public PyObject __sub__(PyObject other) { return baseset___sub__(other); } @@ -124,16 +127,16 @@ final PyObject baseset___sub__(PyObject other) { public PyObject difference(PyObject other) { return baseset_difference(other); } - + final PyObject baseset_difference(PyObject other) { return baseset_difference(new PyObject[] {other}); } - + final PyObject baseset_difference(PyObject [] args) { if (args.length == 0) { return BaseSet.makeNewSet(getType(), this); } - + BaseSet o = BaseSet.makeNewSet(getType(), this); for (PyObject item: args) { BaseSet bs = args[0] instanceof BaseSet ? (BaseSet)item : new PySet(item); @@ -150,13 +153,14 @@ final PyObject baseset_difference(PyObject [] args) { /** * The symmetric difference of the this with other. - *

    - *
    + *

    + * * (I.e. all elements that are in exactly one of the sets) * * @param other A BaseSet instance. * @return The symmetric difference of the two sets as a new set. */ + @Override public PyObject __xor__(PyObject other) { return baseset___xor__(other); } @@ -193,6 +197,7 @@ final PyObject baseset_symmetric_difference(PyObject other) { * * @return The hashCode of the set. */ + @Override public abstract int hashCode(); /** @@ -200,6 +205,7 @@ final PyObject baseset_symmetric_difference(PyObject other) { * * @return The length of the set. */ + @Override public int __len__() { return baseset___len__(); } @@ -214,6 +220,7 @@ final int baseset___len__() { * * @return true if the set is not empty, false otherwise */ + @Override public boolean __nonzero__() { return !_set.isEmpty(); } @@ -223,6 +230,7 @@ public boolean __nonzero__() { * * @return An iteration of the set. */ + @Override public PyObject __iter__() { return baseset___iter__(); } @@ -243,6 +251,7 @@ public PyObject __iternext__() { }; } + @Override public boolean __contains__(PyObject other) { return baseset___contains__(other); } @@ -256,6 +265,7 @@ final boolean baseset___contains__(PyObject other) { } } + @Override public int __cmp__(PyObject other) { return baseset___cmp__(other); } @@ -264,28 +274,61 @@ final int baseset___cmp__(PyObject other) { throw Py.TypeError("cannot compare sets using cmp()"); } + @Override public PyObject __eq__(PyObject other) { return baseset___eq__(other); } final PyObject baseset___eq__(PyObject other) { - if (other instanceof BaseSet) { - return Py.newBoolean(_set.equals(((BaseSet)other)._set)); + // jobj might be Py.NoConversion if other is not a Set + Object jobj = other.__tojava__(Set.class); + if (jobj instanceof Set) { + final Set jSet = (Set) jobj; + // If the sizes differ must be not equal + if (jSet.size() != size()) { + return Py.False; + } + // Now need to perform element comparison + for (Object otherItem : jSet) { + if (!contains(otherItem)) { + return Py.False; // If any item is not contained then they are not equal + } + } + // All items are contained and the lentgh is the same so we are equal + return Py.True; } + // other wasn't a set so not equal return Py.False; } + @Override public PyObject __ne__(PyObject other) { return baseset___ne__(other); } final PyObject baseset___ne__(PyObject other) { - if (other instanceof BaseSet) { - return Py.newBoolean(!_set.equals(((BaseSet)other)._set)); + // jobj might be Py.NoConversion if other is not a Set + Object jobj = other.__tojava__(Set.class); + if (jobj instanceof Set) { + final Set jSet = (Set) jobj; + // If the sizes differ must be not equal + if (jSet.size() != size()) { + return Py.True; + } + // Now need to perform element comparison + for (Object otherItem : jSet) { + if (!contains(otherItem)) { + return Py.True; // If any item is not contained then they are not equal + } + } + // All items are contained and the lentgh is the same so we are equal + return Py.False; } + // other wasn't a set so not equal return Py.True; } + @Override public PyObject __le__(PyObject other) { return baseset___le__(other); } @@ -294,6 +337,7 @@ final PyObject baseset___le__(PyObject other) { return baseset_issubset(asBaseSet(other)); } + @Override public PyObject __ge__(PyObject other) { return baseset___ge__(other); } @@ -302,6 +346,7 @@ final PyObject baseset___ge__(PyObject other) { return baseset_issuperset(asBaseSet(other)); } + @Override public PyObject __lt__(PyObject other) { return baseset___lt__(other); } @@ -311,6 +356,7 @@ final PyObject baseset___lt__(PyObject other) { return Py.newBoolean(size() < bs.size() && baseset_issubset(other).__nonzero__()); } + @Override public PyObject __gt__(PyObject other) { return baseset___gt__(other); } @@ -321,11 +367,12 @@ final PyObject baseset___gt__(PyObject other) { } /** - * Used for pickling. Uses the module setsfactory to + * Used for pickling. Uses the module setsfactory to * export safe constructors. * * @return a tuple of (constructor, (elements)) */ + @Override public PyObject __reduce__() { return baseset___reduce__(); } @@ -344,7 +391,7 @@ final PyObject baseset_union(PyObject other) { result._update(other); return result; } - + final PyObject baseset_union(PyObject [] args) { BaseSet result = BaseSet.makeNewSet(getType(), this); for (PyObject item: args) { @@ -370,13 +417,13 @@ final PyObject baseset_intersection(PyObject other) { PyObject common = __builtin__.filter(big.__getattr__("__contains__"), little); return BaseSet.makeNewSet(getType(), common); } - + final PyObject baseset_intersection(PyObject [] args) { BaseSet result = BaseSet.makeNewSet(getType(), this); if (args.length == 0) { return result; } - + for (PyObject other: args) { result = (BaseSet)result.baseset_intersection(other); } @@ -405,12 +452,13 @@ final PyObject baseset_issuperset(PyObject other) { BaseSet bs = other instanceof BaseSet ? (BaseSet)other : new PySet(other); return bs.baseset_issubset(this); } - + final PyObject baseset_isdisjoint(PyObject other) { BaseSet bs = other instanceof BaseSet ? (BaseSet)other : new PySet(other); return Collections.disjoint(_set, bs._set) ? Py.True : Py.False; } + @Override public String toString() { return baseset_toString(); } @@ -502,30 +550,37 @@ protected static BaseSet makeNewSet(PyType type, PyObject iterable) { return so; } + @Override public int size() { return _set.size(); } + @Override public void clear() { _set.clear(); } + @Override public boolean isEmpty() { return _set.isEmpty(); } + @Override public boolean add(Object o) { return _set.add(Py.java2py(o)); } + @Override public boolean contains(Object o) { return _set.contains(Py.java2py(o)); } + @Override public boolean remove(Object o) { return _set.remove(Py.java2py(o)); } + @Override public boolean addAll(Collection c) { boolean added = false; for (Object object : c) { @@ -534,6 +589,7 @@ public boolean addAll(Collection c) { return added; } + @Override public boolean containsAll(Collection c) { for (Object object : c) { if (!_set.contains(Py.java2py(object))) { @@ -543,6 +599,7 @@ public boolean containsAll(Collection c) { return true; } + @Override public boolean removeAll(Collection c) { boolean removed = false; for (Object object : c) { @@ -551,6 +608,7 @@ public boolean removeAll(Collection c) { return removed; } + @Override public boolean retainAll(Collection c) { boolean modified = false; Iterator e = iterator(); @@ -563,28 +621,34 @@ public boolean retainAll(Collection c) { return modified; } + @Override public Iterator iterator() { return new Iterator() { Iterator real = _set.iterator(); + @Override public boolean hasNext() { return real.hasNext(); } + @Override public Object next() { return Py.tojava(real.next(), Object.class); } + @Override public void remove() { real.remove(); } }; } + @Override public Object[] toArray() { return toArray(new Object[size()]); } + @Override public Object[] toArray(Object a[]) { int size = size(); if (a.length < size) { diff --git a/src/org/python/core/BufferProtocol.java b/src/org/python/core/BufferProtocol.java index 4d5a0d318..701b5d3ff 100644 --- a/src/org/python/core/BufferProtocol.java +++ b/src/org/python/core/BufferProtocol.java @@ -2,19 +2,32 @@ /** * Interface marking an object as capable of exposing its internal state as a {@link PyBuffer}. + *

    + * A few objects implement {@code BufferProtocol} (e.g. by inheritance) but cannot actually provide + * their value as a {@link PyBuffer}. These should throw {@code ClassCastException}, permitting the + * idiom:

    + *     try (PyBuffer buf = ((BufferProtocol) obj).getBuffer(PyBUF.SIMPLE)) {
    + *         ... // Do something with buf
    + *     } catch (ClassCastException e) {
    + *         ... // expected bytes object or buffer not obj.getType()
    + *     }
    + * 
    The {@code catch} is executed identically whether the cause is the explicit cast of + * {@code obj} or {@code getBuffer}, and the try-with-resources releases the buffer if one was + * obtained. */ public interface BufferProtocol { /** * Method by which the consumer requests the buffer from the exporter. The consumer provides - * information on its intended method of navigation and the features the buffer object is asked - * (or assumed) to provide. Each consumer requesting a buffer in this way, when it has finished - * using it, should make a corresponding call to {@link PyBuffer#release()} on the buffer it - * obtained, since some objects alter their behaviour while buffers are exported. - * + * information on its ability to understand buffer navigation. Each consumer requesting a buffer + * in this way, when it has finished using it, should make a corresponding call to + * {@link PyBuffer#release()} on the buffer it obtained, or {@link PyBuffer#close()} using + * try-with-resources, since some objects alter their behaviour while buffers are exported. + * * @param flags specifying features demanded and the navigational capabilities of the consumer * @return exported buffer - * @throws PyException (BufferError) when expectations do not correspond with the buffer + * @throws PyException {@code BufferError} when expectations do not correspond with the buffer + * @throws ClassCastException when the object only formally implements {@code BufferProtocol} */ - PyBuffer getBuffer(int flags) throws PyException; + PyBuffer getBuffer(int flags) throws PyException, ClassCastException; } diff --git a/src/org/python/core/BytecodeLoader.java b/src/org/python/core/BytecodeLoader.java index 07f482e3e..82e7fc658 100644 --- a/src/org/python/core/BytecodeLoader.java +++ b/src/org/python/core/BytecodeLoader.java @@ -1,53 +1,58 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; +import org.objectweb.asm.ClassReader; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; +import java.util.LinkedList; import java.util.List; -import org.objectweb.asm.ClassReader; -import org.python.util.Generic; - /** - * Utility class for loading compiled python modules and java classes defined in python modules. + * Utility class for loading compiled Python modules and Java classes defined in Python modules. */ public class BytecodeLoader { /** - * Turn the java byte code in data into a java class. + * Turn the Java class file data into a Java class. * - * @param name - * the name of the class - * @param data - * the java byte code. - * @param referents - * superclasses and interfaces that the new class will reference. + * @param name fully-qualified binary name of the class + * @param data a class file as a byte array + * @param referents super-classes and interfaces that the new class will reference. */ + @SuppressWarnings("unchecked") public static Class makeClass(String name, byte[] data, Class... referents) { + @SuppressWarnings("resource") Loader loader = new Loader(); for (Class referent : referents) { try { - ClassLoader cur = referent.getClassLoader(); - if (cur != null) { - loader.addParent(cur); - } - } catch (SecurityException e) { - } + loader.addParent(referent.getClassLoader()); + } catch (SecurityException e) {} } Class c = loader.loadClassFromBytes(name, data); + if (ContainsPyBytecode.class.isAssignableFrom(c)) { + try { + fixPyBytecode((Class) c); + } catch (IllegalAccessException | NoSuchFieldException | ClassNotFoundException + | IOException e) { + throw new RuntimeException(e); + } + } BytecodeNotification.notify(name, data, c); return c; } /** - * Turn the java byte code in data into a java class. + * Turn the Java class file data into a Java class. * - * @param name - * the name of the class - * @param referents - * superclasses and interfaces that the new class will reference. - * @param data - * the java byte code. + * @param name the name of the class + * @param referents super-classes and interfaces that the new class will reference. + * @param data a class file as a byte array */ public static Class makeClass(String name, List> referents, byte[] data) { if (referents != null) { @@ -56,20 +61,197 @@ public static Class makeClass(String name, List> referents, byte[] d return makeClass(name, data); } + private static PyCode parseSerializedCode(String code_str) + throws IOException, ClassNotFoundException { + // From Java 8 use: byte[] b = Base64.getDecoder().decode(code_str); + byte[] b = base64decode(code_str); + ByteArrayInputStream bi = new ByteArrayInputStream(b); + ObjectInputStream si = new ObjectInputStream(bi); + PyBytecode meth_code = (PyBytecode) si.readObject(); + si.close(); + bi.close(); + return meth_code; + } + + /** + * Implement a restricted form of base64 decoding compatible with the encoding in Module. This + * decoder treats characters outside the set of 64 necessary to encode data as errors, including + * the pad "=". As a result, the length of the argument exactly determines the size of array + * returned. + * + * @param src to decode + * @return a new byte array + * @throws IllegalArgumentException if src has an invalid character or impossible length. + */ + private static byte[] base64decode(String src) throws IllegalArgumentException { + + // Length L is a multiple of 4 plus 0, 2 or 3 tail characters (bearing 0, 8, or 16 bits) + final int L = src.length(); + final int tail = L % 4; // 0 to 3 where 1 (an extra 6 bits) is invalid. + if (tail == 1) { + throw new IllegalArgumentException("Input length invalid (4n+1)"); + } + + // src encodes exactly this many bytes: + final int N = (L / 4) * 3 + (tail > 0 ? tail - 1 : 0); + byte[] data = new byte[N]; + + // Work through src in blocks of 4 + int s = 0, b = 0, quantum; + while (s <= L - 4) { + // Process src[s:s+4] + quantum = (base64CharToBits(src.charAt(s++)) << 18) + + (base64CharToBits(src.charAt(s++)) << 12) + + (base64CharToBits(src.charAt(s++)) << 6) + base64CharToBits(src.charAt(s++)); + data[b++] = (byte) (quantum >> 16); + data[b++] = (byte) (quantum >> 8); + data[b++] = (byte) quantum; + } + + // Now deal with 2 or 3 tail characters, generating one or two bytes. + if (tail >= 2) { + // Repeat the loop body, but everything is 8 bits to the right. + quantum = (base64CharToBits(src.charAt(s++)) << 10) + + (base64CharToBits(src.charAt(s++)) << 4); + data[b++] = (byte) (quantum >> 8); + if (tail == 3) { + quantum += (base64CharToBits(src.charAt(s++)) >> 2); + data[b++] = (byte) quantum; + } + } + + return data; + } + + /** + * Helper for {@link #base64decode(String)}, converting one character. + * + * @param c to convert + * @return value 0..63 + * @throws IllegalArgumentException if not a base64 character + */ + private static int base64CharToBits(char c) throws IllegalArgumentException { + if (c >= 'a') { + if (c <= 'z') { + return c - 71; // c - 'a' + 26 + } + } else if (c >= 'A') { + if (c <= 'Z') { + return c - 'A'; + } + } else if (c >= '0') { + if (c <= '9') { + return c + 4; // c - '0' + 52 + } + } else if (c == '+') { + return 62; + } else if (c == '/') { + return 63; + } + throw new IllegalArgumentException("Invalid character " + c); + } + + /** + * This method looks for Python-Bytecode stored in String literals. + * While Java supports rather long strings, constrained only by + * int-addressing of arrays, it supports only up to 65535 characters + * in literals (not sure how escape-sequences are counted). + * To circumvent this limitation, the code is automatically splitted + * into several literals with the following naming-scheme. + * + * - The marker-interface 'ContainsPyBytecode' indicates that a class + * contains (static final) literals of the following scheme: + * - a prefix of '___' indicates a bytecode-containing string literal + * - a number indicating the number of parts follows + * - '0_' indicates that no splitting occurred + * - otherwise another number follows, naming the index of the literal + * - indexing starts at 0 + * + * Examples: + * ___0_method1 contains bytecode for method1 + * ___2_0_method2 contains first part of method2's bytecode + * ___2_1_method2 contains second part of method2's bytecode + * + * Note that this approach is provisional. In future, Jython might contain + * the bytecode directly as bytecode-objects. The current approach was + * feasible with much less complicated JVM bytecode-manipulation, but needs + * special treatment after class-loading. + */ + public static void fixPyBytecode(Class c) + throws IllegalAccessException, NoSuchFieldException, java.io.IOException, + ClassNotFoundException { + Field[] fields = c.getDeclaredFields(); + for (Field fld: fields) { + String fldName = fld.getName(); + if (fldName.startsWith("___")) { + fldName = fldName.substring(3); + + String[] splt = fldName.split("_"); + if (splt[0].equals("0")) { + fldName = fldName.substring(2); + Field codeField = c.getDeclaredField(fldName); + if (codeField.get(null) == null) { + codeField.set(null, parseSerializedCode((String) fld.get(null))); + } + } else { + if (splt[1].equals("0")) { + fldName = fldName.substring(splt[0].length()+splt[1].length()+2); + Field codeField = c.getDeclaredField(fldName); + if (codeField.get(null) == null) { + // assemble original code-string: + int len = Integer.parseInt(splt[0]); + StringBuilder blt = new StringBuilder((String) fld.get(null)); + int pos = 1, pos0; + String partName; + while (pos < len) { + pos0 = pos; + for (Field fldPart: fields) { + partName = fldPart.getName(); + if (partName.length() != fldName.length() && + partName.startsWith("___") && + partName.endsWith(fldName)) { + String[] splt2 = partName.substring(3).split("_"); + if (Integer.parseInt(splt2[1]) == pos) { + blt.append((String) fldPart.get(null)); + pos += 1; + if (pos == len) { + break; + } + } + } + } + if (pos0 == pos) { + throw new RuntimeException( + "Invalid PyBytecode splitting in " + c.getName() + + ":\nSplit-index " + pos + " wasn't found."); + } + } + codeField.set(null, parseSerializedCode(blt.toString())); + } + } + } + } + } + } + /** - * Turn the java byte code for a compiled python module into a java class. + * Turn the Java class file data for a compiled Python module into a {@code PyCode} object, by + * constructing an instance of the named class and calling the instance's + * {@link PyRunnable#getMain()}. * - * @param name - * the name of the class - * @param data - * the java byte code. + * @param name fully-qualified binary name of the class + * @param data a class file as a byte array + * @param filename to provide to the constructor of the named class + * @return the {@code PyCode} object produced by the named class' {@code getMain} */ public static PyCode makeCode(String name, byte[] data, String filename) { try { Class c = makeClass(name, data); - Object o = c.getConstructor(new Class[] {String.class}) - .newInstance(new Object[] {filename}); - return ((PyRunnable)o).getMain(); + // A compiled module has a constructor taking a String filename argument. + Constructor cons = c.getConstructor(new Class[] {String.class}); + Object instance = cons.newInstance(new Object[] {filename}); + PyCode result = ((PyRunnable) instance).getMain(); + return result; } catch (Exception e) { throw Py.JavaError(e); } @@ -77,16 +259,17 @@ public static PyCode makeCode(String name, byte[] data, String filename) { public static class Loader extends URLClassLoader { - private List parents = Generic.list(); + private LinkedList parents = new LinkedList<>(); public Loader() { super(new URL[0]); parents.add(imp.getSyspathJavaLoader()); } + /** Add given loader at the front of the list of the parent list (if not {@code null}). */ public void addParent(ClassLoader referent) { - if (!parents.contains(referent)) { - parents.add(0, referent); + if (referent != null && !parents.contains(referent)) { + parents.addFirst(referent); } } @@ -105,6 +288,15 @@ protected Class loadClass(String name, boolean resolve) throws ClassNotFoundE throw new ClassNotFoundException(name); } + /** + * Define the named class using the class file data provided, and resolve it. (See JVM + * specification.) For class names ending "$py", this method may adjust that name to that + * found in the class file itself. + * + * @param name fully-qualified binary name of the class + * @param data a class file as a byte array + * @return the defined and resolved class + */ public Class loadClassFromBytes(String name, byte[] data) { if (name.endsWith("$py")) { try { diff --git a/src/org/python/core/BytecodeNotification.java b/src/org/python/core/BytecodeNotification.java index d70893322..aaa157d4c 100644 --- a/src/org/python/core/BytecodeNotification.java +++ b/src/org/python/core/BytecodeNotification.java @@ -1,17 +1,16 @@ package org.python.core; +import java.io.ByteArrayOutputStream; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.Collections; -import java.io.ByteArrayOutputStream; /** * Notifies registered callbacks if new bytecode is loaded. */ public class BytecodeNotification { /** - * Interface for callbacks. - * Notifies the name of the loaded class, raw bytes of the class, + * Interface for callbacks. + * Notifies the name of the loaded class, raw bytes of the class, * and the Java class object. */ public interface Callback { @@ -19,8 +18,8 @@ public interface Callback { } /** - * The following list stores register callback objects. - * The list is shared among the PySystemState objects + * The following list stores register callback objects. + * The list is shared among the PySystemState objects * if there are multiple instances. */ private static List callbacks = new CopyOnWriteArrayList(); @@ -28,6 +27,7 @@ public interface Callback { static { // Maintain legacy behavior register(new Callback() { + @Override public void notify(String name, byte[] bytes, Class c) { if (Options.proxyDebugDirectory == null || (!name.startsWith("org.python.pycode.") && @@ -52,11 +52,11 @@ public void notify(String name, byte[] bytes, Class c) { * Unregisters the callback object * * @param n the callback object - * @return true if successfully removed and + * @return true if successfully removed and * false if the callback object was not registered */ public static boolean unregister(Callback n) { return callbacks.remove(n); } - + /** * Clears all the registered callbacks */ @@ -67,14 +67,14 @@ public void notify(String name, byte[] bytes, Class c) { * * @param name the name of the class of the new bytecode * @param data raw byte data of the class - * @param class Java class object of the new bytecode + * @param klass Java class object of the new bytecode */ public static void notify(String name, byte[] data, Class klass) { - for (Callback c:callbacks) { + for (Callback c : callbacks) { try { c.notify(name, data, klass); } catch (Exception e) { - Py.writeWarning("BytecodeNotification", "Exception from callback:"+e); + Py.writeWarning("BytecodeNotification", "Exception from callback:" + e); } } } diff --git a/src/org/python/core/ClasspathPyImporter.java b/src/org/python/core/ClasspathPyImporter.java index 34032a74f..04b23ead6 100644 --- a/src/org/python/core/ClasspathPyImporter.java +++ b/src/org/python/core/ClasspathPyImporter.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.Map; +import java.util.logging.Level; import org.python.core.util.FileUtil; import org.python.core.util.StringUtil; @@ -213,9 +214,10 @@ protected String makeEntry(String filename) { return null; } - private InputStream tryClassLoader(String fullFilename, ClassLoader loader, String name) { + private InputStream tryClassLoader(String fullFilename, ClassLoader loader, String place) { if (loader != null) { - Py.writeDebug("import", "trying " + fullFilename + " in " + name + " class loader"); + logger.log(Level.FINE, "# trying {0} in {1} class loader", + new Object[] {fullFilename, place}); return loader.getResourceAsStream(fullFilename); } return null; diff --git a/src/org/python/core/Console.java b/src/org/python/core/Console.java index 88d274029..dfa7a87fa 100644 --- a/src/org/python/core/Console.java +++ b/src/org/python/core/Console.java @@ -11,6 +11,8 @@ * use on the console. Such a class may provide line editing and history recall to an interactive * console. A default implementation (that does not provide any such facilities) is available as * {@link PlainConsole}. + * + * @see org.python.core.RegistryKey#PYTHON_CONSOLE */ public interface Console { diff --git a/src/org/python/core/ContainsPyBytecode.java b/src/org/python/core/ContainsPyBytecode.java new file mode 100644 index 000000000..379862a43 --- /dev/null +++ b/src/org/python/core/ContainsPyBytecode.java @@ -0,0 +1,34 @@ +package org.python.core; + +/** + * Jython stores Python-Bytecode of methods and functions that exceed + * JVM method-size restrictions in String literals. + * While Java supports rather long strings, constrained only by + * int-addressing of arrays, it supports only up to 65535 characters + * in literals (not sure how escape-sequences are counted). + * To circumvent this limitation, the code is automatically splitted + * into several literals with the following naming-scheme. + * + * - The marker-interface 'ContainsPyBytecode' indicates that a class + * contains (static final) literals of the following scheme: + * - a prefix of '___' indicates a bytecode-containing string literal + * - a number indicating the number of parts follows + * - '0_' indicates that no splitting occurred + * - otherwise another number follows, naming the index of the literal + * - indexing starts at 0 + * + * Examples: + * ___0_method1 contains bytecode for method1 + * ___2_0_method2 contains first part of method2's bytecode + * ___2_1_method2 contains second part of method2's bytecode + * + * Note that this approach is provisional. In future, Jython might contain + * the bytecode directly as bytecode-objects. The current approach was + * feasible with much less complicated JVM bytecode-manipulation, but needs + * special treatment after class-loading. + * + * In a future approach this interface might be removed. + */ +public interface ContainsPyBytecode { + // For now this is a pure marker-interface. +} diff --git a/src/org/python/core/Deriveds.java b/src/org/python/core/Deriveds.java index d6a90b038..ebf65666a 100644 --- a/src/org/python/core/Deriveds.java +++ b/src/org/python/core/Deriveds.java @@ -1,4 +1,5 @@ -/* Copyright (c) Jython Developers */ +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; /** @@ -46,19 +47,10 @@ public static PyObject __findattr_ex__(PyObject self, String name) { // pass through to __getattr__ } else { PyObject getattribute = type.lookup("__getattribute__"); - // This is a horrible hack for eventual consistency of the cache. We hope that the cached version - // becomes available, but don't wait forever. - for (int i = 0; i < 100000; i++) { - if (getattribute != null) { - break; - } - getattribute = type.lookup("__getattribute__"); - } if (getattribute == null) { - // This shouldn't happen - throw Py.SystemError(String.format( - "__getattribute__ not found on type %s. See http://bugs.jython.org/issue2487 for details.", - type.getName())); + // This shouldn't happen (and isn't always to do with bjo #2487 when it does). + throw Py.SystemError( + String.format("__getattribute__ not found on type %s", type.getName())); } if (getattribute == objectGetattribute) { type.setUsesObjectGetattribute(true); diff --git a/src/org/python/core/FunctionThread.java b/src/org/python/core/FunctionThread.java index 500210772..ea3935991 100644 --- a/src/org/python/core/FunctionThread.java +++ b/src/org/python/core/FunctionThread.java @@ -2,8 +2,6 @@ import java.util.concurrent.atomic.AtomicInteger; -import org.python.modules._systemrestart; - public class FunctionThread extends Thread { private final PyObject func; @@ -24,7 +22,7 @@ public void run() { try { func.__call__(args); } catch (PyException exc) { - if (exc.match(Py.SystemExit) || exc.match(_systemrestart.SystemRestart)) { + if (exc.match(Py.SystemExit)) { return; } Py.stderr.println("Unhandled exception in thread started by " + func); diff --git a/src/org/python/core/JavaImportHelper.java b/src/org/python/core/JavaImportHelper.java index 633c4b4a1..10d944e49 100644 --- a/src/org/python/core/JavaImportHelper.java +++ b/src/org/python/core/JavaImportHelper.java @@ -1,220 +1,220 @@ -package org.python.core; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; - -/** - * Helper class handling the VM specific java package detection. - */ -public class JavaImportHelper { - - private static final String DOT = "."; - - /** - * Try to add the java package. - *

    - * This is handy in cases where the package scan cannot run, or when the initial classpath does not contain all .jar - * files (such as in J2EE containers). - *

    - * There is some self-healing in the sense that a correct, explicit import of a java class will succeed even if - * sys.modules already contains a Py.None entry for the corresponding java package. - * - * @param packageName The dotted name of the java package - * @param fromlist A tuple with the from names to import. Can be null or empty. - * - * @return true if a java package was doubtlessly identified and added, false - * otherwise. - */ - protected static boolean tryAddPackage(final String packageName, PyObject fromlist) { - // make sure we do not turn off the added flag, once it is set - boolean packageAdded = false; - - if (packageName != null) { - // check explicit imports first (performance optimization) - - // handle 'from java.net import URL' like explicit imports - List stringFromlist = getFromListAsStrings(fromlist); - for (String fromName : stringFromlist) { - if (isJavaClass(packageName, fromName)) { - packageAdded = addPackage(packageName, packageAdded); - - } - } - - // handle 'import java.net.URL' style explicit imports - int dotPos = packageName.lastIndexOf(DOT); - if (dotPos > 0) { - String lastDottedName = packageName.substring(dotPos + 1); - String packageCand = packageName.substring(0, dotPos); - if (isJavaClass(packageCand, lastDottedName)) { - packageAdded = addPackage(packageCand, packageAdded); - } - } - - // if all else fails, check already loaded packages - if (!packageAdded) { - // build the actual map with the packages known to the VM - Map packages = buildLoadedPackages(); - - // add known packages - String parentPackageName = packageName; - if (isLoadedPackage(packageName, packages)) { - packageAdded = addPackage(packageName, packageAdded); - } - dotPos = 0; - do { - dotPos = parentPackageName.lastIndexOf(DOT); - if (dotPos > 0) { - parentPackageName = parentPackageName.substring(0, dotPos); - if (isLoadedPackage(parentPackageName, packages)) { - packageAdded = addPackage(parentPackageName, packageAdded); - } - } - } while (dotPos > 0); - - // handle package imports like 'from java import math' - for (String fromName : stringFromlist) { - String fromPackageName = packageName + DOT + fromName; - if (isLoadedPackage(fromPackageName, packages)) { - packageAdded = addPackage(fromPackageName, packageAdded); - } - } - } - } - return packageAdded; - } - - /** - * Check if a java package is already known to the VM. - *

    - * May return false even if the given package name is a valid java package ! - * - * @param packageName - * - * @return true if the package with the given name is already loaded by the VM, false - * otherwise. - */ - protected static boolean isLoadedPackage(String packageName) { - return isLoadedPackage(packageName, buildLoadedPackages()); - } - - /** - * Convert the fromlist into a java.lang.String based list. - *

    - * Do some sanity checks: filter out '*' and empty tuples, as well as non tuples. - * - * @param fromlist - * @return a list containing java.lang.String entries - */ - private static final List getFromListAsStrings(PyObject fromlist) { - List stringFromlist = new ArrayList(); - - if (fromlist != null && fromlist != Py.EmptyTuple && fromlist instanceof PyTuple) { - Iterator iterator = ((PyTuple) fromlist).iterator(); - while (iterator.hasNext()) { - Object obj = iterator.next(); - if (obj instanceof PyString) { - obj = ((PyString) obj).getString(); - } - if (obj instanceof String) { - String fromName = (String) obj; - if (!"*".equals(fromName)) { - stringFromlist.add(fromName); - } - } - } - } - return stringFromlist; - } - - /** - * Faster way to check if a java package is already known to the VM. - *

    - * May return false even if the given package name is a valid java package ! - * - * @param packageName - * @param packages A Map containing all packages actually known to the VM. Such a Map can be obtained using - * {@link JavaImportHelper.buildLoadedPackagesTree()} - * - * @return true if the package with the given name is already loaded by the VM, false - * otherwise. - */ - private static boolean isLoadedPackage(String javaPackageName, Map packages) { - boolean isLoaded = false; - if (javaPackageName != null) { - isLoaded = packages.containsKey(javaPackageName); - } - return isLoaded; - } - - /** - * Build a Map of the currently known packages to the VM. - *

    - * All parent packages appear as single entries like python modules, e.g. java, - * java.lang, java.lang.reflect, - */ - private static Map buildLoadedPackages() { - TreeMap packageMap = new TreeMap(); - Package[] packages = Package.getPackages(); - for (int i = 0; i < packages.length; i++) { - String packageName = packages[i].getName(); - packageMap.put(packageName, ""); - int dotPos = 0; - do { - dotPos = packageName.lastIndexOf(DOT); - if (dotPos > 0) { - packageName = packageName.substring(0, dotPos); - packageMap.put(packageName, ""); - } - } while (dotPos > 0); - } - return packageMap; - } - - /** - * @return true if the java class can be found by the current - * Py classloader setup - */ - private static boolean isJavaClass(String packageName, String className) { - return className != null && className.length() > 0 - && Py.findClass(packageName + "." + className) != null; - } - - /** - * Add a java package to sys.modules, if not already done - * - * @return true if something was really added, false otherwise - */ - private static boolean addPackage(String packageName, boolean packageAdded) { - PyObject modules = Py.getSystemState().modules; - String internedPackageName = packageName.intern(); - PyObject module = modules.__finditem__(internedPackageName); - // a previously failed import could have created a Py.None entry in sys.modules - if (module == null || module == Py.None) { - int dotPos = 0; - do { - PyJavaPackage p = PySystemState.add_package(packageName); - if(dotPos == 0) { - modules.__setitem__(internedPackageName, p); - } else { - module = modules.__finditem__(internedPackageName); - if (module == null || module == Py.None) { - modules.__setitem__(internedPackageName, p); - } - } - dotPos = packageName.lastIndexOf(DOT); - if (dotPos > 0) { - packageName = packageName.substring(0, dotPos); - internedPackageName = packageName.intern(); - } - } while(dotPos > 0); - // make sure not to turn off the packageAdded flag - packageAdded = true; - } - return packageAdded; - } - -} +package org.python.core; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * Helper class handling the VM specific java package detection. + */ +public class JavaImportHelper { + + private static final String DOT = "."; + + /** + * Try to add the java package. + *

    + * This is handy in cases where the package scan cannot run, or when the initial classpath does + * not contain all .jar files (such as in J2EE containers). + *

    + * There is some self-healing in the sense that a correct, explicit import of a java class will + * succeed even if sys.modules already contains a Py.None entry for the corresponding java + * package. + * + * @param packageName The dotted name of the java package + * @param fromlist A tuple with the from names to import. Can be null or empty. + * + * @return true if a java package was doubtlessly identified and added, + * false otherwise. + */ + protected static boolean tryAddPackage(final String packageName, PyObject fromlist) { + // make sure we do not turn off the added flag, once it is set + boolean packageAdded = false; + + if (packageName != null) { + // check explicit imports first (performance optimization) + + // handle 'from java.net import URL' like explicit imports + List stringFromlist = getFromListAsStrings(fromlist); + for (String fromName : stringFromlist) { + if (isJavaClass(packageName, fromName)) { + packageAdded = addPackage(packageName, packageAdded); + } + } + + // handle 'import java.net.URL' style explicit imports + int dotPos = packageName.lastIndexOf(DOT); + if (dotPos > 0) { + String lastDottedName = packageName.substring(dotPos + 1); + String packageCand = packageName.substring(0, dotPos); + if (isJavaClass(packageCand, lastDottedName)) { + packageAdded = addPackage(packageCand, packageAdded); + } + } + + // if all else fails, check already loaded packages + if (!packageAdded) { + // build the actual map with the packages known to the VM + Map packages = buildLoadedPackages(); + + // add known packages + String parentPackageName = packageName; + if (isLoadedPackage(packageName, packages)) { + packageAdded = addPackage(packageName, packageAdded); + } + dotPos = 0; + do { + dotPos = parentPackageName.lastIndexOf(DOT); + if (dotPos > 0) { + parentPackageName = parentPackageName.substring(0, dotPos); + if (isLoadedPackage(parentPackageName, packages)) { + packageAdded = addPackage(parentPackageName, packageAdded); + } + } + } while (dotPos > 0); + + // handle package imports like 'from java import math' + for (String fromName : stringFromlist) { + String fromPackageName = packageName + DOT + fromName; + if (isLoadedPackage(fromPackageName, packages)) { + packageAdded = addPackage(fromPackageName, packageAdded); + } + } + } + } + return packageAdded; + } + + /** + * Check if a java package is already known to the VM. + *

    + * May return false even if the given package name is a valid java package ! + * + * @param packageName + * + * @return true if the package with the given name is already loaded by the VM, + * false otherwise. + */ + protected static boolean isLoadedPackage(String packageName) { + return isLoadedPackage(packageName, buildLoadedPackages()); + } + + /** + * Convert the fromlist into a java.lang.String based list. + *

    + * Do some sanity checks: filter out '*' and empty tuples, as well as non tuples. + * + * @param fromlist + * @return a list containing java.lang.String entries + */ + private static final List getFromListAsStrings(PyObject fromlist) { + List stringFromlist = new ArrayList(); + + if (fromlist != null && fromlist != Py.EmptyTuple && fromlist instanceof PyTuple) { + Iterator iterator = ((PyTuple) fromlist).iterator(); + while (iterator.hasNext()) { + Object obj = iterator.next(); + if (obj instanceof PyString) { + obj = ((PyString) obj).getString(); + } + if (obj instanceof String) { + String fromName = (String) obj; + if (!"*".equals(fromName)) { + stringFromlist.add(fromName); + } + } + } + } + return stringFromlist; + } + + /** + * Faster way to check if a java package is already known to the VM. + *

    + * May return false even if the given package name is a valid java package ! + * + * @param packageName + * @param packages A Map containing all packages actually known to the VM. Such a Map can be + * obtained using {@link JavaImportHelper.buildLoadedPackagesTree()} + * + * @return true if the package with the given name is already loaded by the VM, + * false otherwise. + */ + private static boolean isLoadedPackage(String javaPackageName, Map packages) { + boolean isLoaded = false; + if (javaPackageName != null) { + isLoaded = packages.containsKey(javaPackageName); + } + return isLoaded; + } + + /** + * Build a Map of the currently known packages to the VM. + *

    + * All parent packages appear as single entries like python modules, e.g. java, + * java.lang, java.lang.reflect, + */ + private static Map buildLoadedPackages() { + TreeMap packageMap = new TreeMap(); + Package[] packages = Package.getPackages(); + for (int i = 0; i < packages.length; i++) { + String packageName = packages[i].getName(); + packageMap.put(packageName, ""); + int dotPos = 0; + do { + dotPos = packageName.lastIndexOf(DOT); + if (dotPos > 0) { + packageName = packageName.substring(0, dotPos); + packageMap.put(packageName, ""); + } + } while (dotPos > 0); + } + return packageMap; + } + + /** + * Try to load packageName.className and return {@code true} if successful. + * + * @return true if the java class can be found by the current Py classloader setup + */ + private static boolean isJavaClass(String packageName, String className) { + return className != null && className.length() > 0 + && Py.findClass(packageName + "." + className) != null; + } + + /** + * Add a java package to sys.modules, if not already done. + * + * @return true if something was really added, false otherwise + */ + private static boolean addPackage(String packageName, boolean packageAdded) { + PyObject modules = Py.getSystemState().modules; + String internedPackageName = packageName.intern(); + PyObject module = modules.__finditem__(internedPackageName); + // a previously failed import could have created a Py.None entry in sys.modules + if (module == null || module == Py.None) { + int dotPos = 0; + do { + PyJavaPackage p = PySystemState.add_package(packageName); + if(dotPos == 0) { + modules.__setitem__(internedPackageName, p); + } else { + module = modules.__finditem__(internedPackageName); + if (module == null || module == Py.None) { + modules.__setitem__(internedPackageName, p); + } + } + dotPos = packageName.lastIndexOf(DOT); + if (dotPos > 0) { + packageName = packageName.substring(0, dotPos); + internedPackageName = packageName.intern(); + } + } while(dotPos > 0); + // make sure not to turn off the packageAdded flag + packageAdded = true; + } + return packageAdded; + } +} diff --git a/src/org/python/core/JavaImporter.java b/src/org/python/core/JavaImporter.java index 6ea381684..b8377ef68 100644 --- a/src/org/python/core/JavaImporter.java +++ b/src/org/python/core/JavaImporter.java @@ -1,5 +1,8 @@ package org.python.core; +import java.util.logging.Logger; +import java.util.logging.Level; + /** * Load Java classes. */ @@ -7,7 +10,9 @@ public class JavaImporter extends PyObject { public static final String JAVA_IMPORT_PATH_ENTRY = "__classpath__"; + private static Logger log = Logger.getLogger("org.python.import"); + @Override public PyObject __call__(PyObject args[], String keywords[]) { if(args[0].toString().endsWith(JAVA_IMPORT_PATH_ENTRY)){ return this; @@ -35,11 +40,11 @@ public PyObject find_module(String name) { * otherwise */ public PyObject find_module(String name, PyObject path) { - Py.writeDebug("import", "trying " + name - + " in packagemanager for path " + path); + log.log(Level.FINE, "# trying {0} in package manager for path {1}", + new Object[] {name, path}); PyObject ret = PySystemState.packageManager.lookupName(name.intern()); if (ret != null) { - Py.writeComment("import", "'" + name + "' as java package"); + log.log(Level.CONFIG, "import {0} # as java package", name); return this; } return Py.None; @@ -54,6 +59,7 @@ public PyObject load_module(String name) { * * @return a string representation of the object. */ + @Override public String toString() { return this.getType().toString(); } diff --git a/src/org/python/core/JavaProxyList.java b/src/org/python/core/JavaProxyList.java index fdf624e9a..0ca502eed 100644 --- a/src/org/python/core/JavaProxyList.java +++ b/src/org/python/core/JavaProxyList.java @@ -1,12 +1,5 @@ package org.python.core; -/** - * Proxy Java objects implementing java.util.List with Python methods - * corresponding to the standard list type - */ - -import org.python.util.Generic; - import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -16,7 +9,12 @@ import java.util.List; import java.util.ListIterator; +import org.python.util.Generic; +/** + * Proxy Java objects implementing java.util.List with Python methods corresponding to the standard + * list type + */ class JavaProxyList { @Untraversable @@ -35,13 +33,73 @@ protected List asList() { protected List newList() { try { - return (List) asList().getClass().newInstance(); - } catch (IllegalAccessException e) { - throw Py.JavaError(e); - } catch (InstantiationException e) { + return (List) asList().getClass().getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { throw Py.JavaError(e); } } + + /** + * Compares this object with other to check for equality. Used to implement __eq __ and + * __ne__. May return null if the other object cannot be compared i.e. is not a Python list + * or Java List. + * + * @param other The object to compare to this + * @return true is equal, false if not equal and null if we can't compare + */ + protected PyBoolean isEqual(PyObject other) { + if (isPyList(other)) { + // Being compared to a Python list + PyList oList = (PyList) other; + List jList = asList(); + if (jList.size() != oList.size()) { + // Size mismatched so not equal + return Py.False; + } + for (int i = 0; i < jList.size(); i++) { + // Do element by element comparison, if any elements are not equal return false + if (!Py.java2py(jList.get(i))._eq(oList.pyget(i)).__nonzero__()) { + return Py.False; + } + } + // All elements are equal so the lists are equal + return Py.True; + } else { + // Being compared to something that is not a Python list + Object oj = other.getJavaProxy(); + if (oj instanceof List) { + // Being compared to a Java List + List oList = (List) oj; + List jList = asList(); + if (jList.size() != oList.size()) { + // Size mismatched so not equal + return Py.False; + } + for (int i = 0; i < jList.size(); i++) { + /* + * Do element by element comparison, if any elements are not equal return + * false. + */ + if (!Py.java2py(jList.get(i))._eq(Py.java2py(oList.get(i))).__nonzero__()) { + return Py.False; + } + } + // All elements are equal so the lists are equal + return Py.True; + } else { + /* + * other is not a Python or Java list, so we don't know if were equal therefore + * return null. + */ + return null; + } + } + } + + private boolean isPyList(PyObject object) { + return object.getType().isSubType(PyList.TYPE); + } } protected static class ListIndexDelegate extends SequenceIndexDelegate { @@ -70,8 +128,9 @@ public PyObject getSlice(int start, int stop, int step) { int n = PySequence.sliceLength(start, stop, step); List newList; try { - newList = list.getClass().newInstance(); - } catch (Exception e) { + newList = list.getClass().getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { throw Py.JavaError(e); } int j = 0; @@ -257,6 +316,7 @@ private static class KVComparator implements Comparator { this.cmp = cmp; } + @Override public int compare(KV o1, KV o2) { int result; if (cmp != null && cmp != Py.None) { @@ -274,6 +334,7 @@ public int compare(KV o1, KV o2) { return result; } + @Override public boolean equals(Object o) { if (o == this) { return true; @@ -339,38 +400,23 @@ public PyObject __call__(PyObject key) { private static final PyBuiltinMethodNarrow listEqProxy = new ListMethod("__eq__", 1) { @Override public PyObject __call__(PyObject other) { - List jList = asList(); - if (other.getType().isSubType(PyList.TYPE)) { - PyList oList = (PyList) other; - if (jList.size() != oList.size()) { - return Py.False; - } - for (int i = 0; i < jList.size(); i++) { - if (!Py.java2py(jList.get(i))._eq(oList.pyget(i)).__nonzero__()) { - return Py.False; - } - } - return Py.True; - } else { - Object oj = other.getJavaProxy(); - if (oj instanceof List) { - List oList = (List) oj; - if (jList.size() != oList.size()) { - return Py.False; - } - for (int i = 0; i < jList.size(); i++) { - if (!Py.java2py(jList.get(i))._eq( - Py.java2py(oList.get(i))).__nonzero__()) { - return Py.False; - } - } - return Py.True; - } else { - return null; - } + return isEqual(other); + } + }; + + private static final PyBuiltinMethodNarrow listNeProxy = new ListMethod("__ne__", 1) { + @Override + public PyObject __call__(PyObject other) { + // isEqual may return null if we don't know how to compare to other. + PyBoolean equal = isEqual(other); + if (equal != null) { + // implement NOT equal by the inverse of equal + return equal.__not__(); } + return null; } }; + private static final PyBuiltinMethodNarrow listAppendProxy = new ListMethod("append", 1) { @Override public PyObject __call__(PyObject value) { @@ -508,10 +554,9 @@ public PyObject __call__(PyObject obj) { List jList = asList(); List jClone; try { - jClone = (List) jList.getClass().newInstance(); - } catch (IllegalAccessException e) { - throw Py.JavaError(e); - } catch (InstantiationException e) { + jClone = (List) jList.getClass().getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { throw Py.JavaError(e); } for (Object entry : jList) { @@ -618,6 +663,7 @@ static PyBuiltinMethod[] getProxyMethods() { listGetProxy, listSetProxy, listEqProxy, + listNeProxy, listRemoveProxy, listAppendProxy, listExtendProxy, @@ -630,13 +676,13 @@ static PyBuiltinMethod[] getProxyMethods() { listIAddProxy, new ListMulProxyClass("__mul__", 1), new ListMulProxyClass("__rmul__", 1), - listIMulProxy, - listSortProxy, + listIMulProxy }; } static PyBuiltinMethod[] getPostProxyMethods() { return new PyBuiltinMethod[]{ + listSortProxy, listRemoveOverrideProxy }; } diff --git a/src/org/python/core/JavaProxyMap.java b/src/org/python/core/JavaProxyMap.java index c0c0a4b75..efbcd2d84 100644 --- a/src/org/python/core/JavaProxyMap.java +++ b/src/org/python/core/JavaProxyMap.java @@ -1,17 +1,21 @@ package org.python.core; +import java.lang.reflect.Constructor; +import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; /** - * Proxy Java objects implementing java.util.List with Python methods - * corresponding to the standard list type + * Proxy Java objects implementing java.util.List with Python methods corresponding to the standard + * list type */ class JavaProxyMap { @Untraversable private static class MapMethod extends PyBuiltinMethodNarrow { + protected MapMethod(String name, int numArgs) { super(name, numArgs); } @@ -27,6 +31,7 @@ protected Map asMap() { @Untraversable private static class MapClassMethod extends PyBuiltinClassMethodNarrow { + protected MapClassMethod(String name, int minArgs, int maxArgs) { super(name, minArgs, maxArgs); } @@ -36,43 +41,102 @@ protected Class asClass() { } } - private static PyObject mapEq(PyObject self, PyObject other) { - Map selfMap = ((Map) self.getJavaProxy()); - if (other.getType().isSubType(PyDictionary.TYPE)) { + /** + * Compares this object with other to check for equality. Used to implement __eq __ and __ne__. + * May return null if the other object cannot be compared i.e. is not a Python dict or Java Map. + * + * @param other The object to compare to this + * @return true is equal, false if not equal and null if we can't compare + */ + private static PyBoolean mapEq(PyObject self, PyObject other) { + if (isPyDict(other)) { + // Being compared to Python dict PyDictionary oDict = (PyDictionary) other; + Map selfMap = (Map) self.getJavaProxy(); if (selfMap.size() != oDict.size()) { + // Map/dict are different sizes therefore not equal return Py.False; } - for (Object jkey : selfMap.keySet()) { - Object jval = selfMap.get(jkey); - PyObject oVal = oDict.__finditem__(Py.java2py(jkey)); + // Loop through all entries checking the keys and values are matched + for (Entry entry : selfMap.entrySet()) { + Object k = entry.getKey(); + Object v = entry.getValue(); + PyObject oVal = oDict.__finditem__(Py.java2py(k)); if (oVal == null) { + // No value for this key in oDict, therefore not equal return Py.False; } - if (!Py.java2py(jval)._eq(oVal).__nonzero__()) { + if (!Py.java2py(v)._eq(oVal).__nonzero__()) { + // The values for this key differ therefore not equal return Py.False; } } + // All keys and values are equal therefore map/dict are equal return Py.True; } else { + // Being compared to something that is not a Python dict Object oj = other.getJavaProxy(); if (oj instanceof Map) { - Map oMap = (Map) oj; - return Py.newBoolean(selfMap.equals(oMap)); + // Being compared to a Java Map convert to Python + Map map = (Map) oj; + final Map pyMap = new HashMap<>(); + for (Entry el : map.entrySet()) { + pyMap.put(Py.java2py(el.getKey()), Py.java2py(el.getValue())); + } + // Compare again this time after conversion to Python dict + return mapEq(self, new PyDictionary(pyMap)); } else { + /* + * other is not a Python dict or Java Map, so we don't know if were equal therefore + * return null + */ return null; } } } - // Map ordering comparisons (lt, le, gt, ge) are based on the key sets; - // we just define mapLe + mapEq for total ordering of such key sets + private static boolean isPyDict(PyObject object) { + return object.getType().isSubType(PyDictionary.TYPE); + } + + /** + * Substitute for {@link Py#tojava(PyObject, Class)} when the second argument is + * {@code Object.class}, and in which we allow a {@code null} argument to signify {@code None}, + * since {@code null} is then the return value. + */ + private static Object tojava(PyObject pyo) { + return (pyo == null || pyo == Py.None) ? null : Py.tojava(pyo, Object.class); + } + + /** Return Python {@code ValueError} that None is not allowed. */ + private static RuntimeException nullException() { + return Py.ValueError("None is not allowed: underlying container cannot store Java null."); + } + + /** + * Return Python {@code ValueError} that None is not allowed, or the + * {@code NullPointerException}, if in fact the value was not {@code None}. + * + * @param npe original exception + * @param key possibly causing the problem + * @param value possibly causing the problem + * @return the Python {@code ValueError} + */ + private static RuntimeException nullException(NullPointerException npe, Object key, + Object value) { + return (key == Py.None || value == Py.None) ? nullException() : npe; + } + + /* + * Map ordering comparisons (lt, le, gt, ge) are based on the key sets; we just define mapLe + + * mapEq for total ordering of such key sets + */ private static PyObject mapLe(PyObject self, PyObject other) { Set selfKeys = ((Map) self.getJavaProxy()).keySet(); if (other.getType().isSubType(PyDictionary.TYPE)) { PyDictionary oDict = (PyDictionary) other; - for (Object jkey : selfKeys) { - if (!oDict.__contains__(Py.java2py(jkey))) { + for (Object k : selfKeys) { + if (!oDict.__contains__(Py.java2py(k))) { return Py.False; } } @@ -80,8 +144,8 @@ private static PyObject mapLe(PyObject self, PyObject other) { } else { Object oj = other.getJavaProxy(); if (oj instanceof Map) { - Map oMap = (Map) oj; - return Py.newBoolean(oMap.keySet().containsAll(selfKeys)); + Map map = (Map) oj; + return Py.newBoolean(map.keySet().containsAll(selfKeys)); } else { return null; } @@ -90,77 +154,109 @@ private static PyObject mapLe(PyObject self, PyObject other) { // Map doesn't extend Collection, so it needs its own version of len, iter and contains private static final PyBuiltinMethodNarrow mapLenProxy = new MapMethod("__len__", 0) { + @Override public PyObject __call__() { return Py.java2py(asMap().size()); } }; private static final PyBuiltinMethodNarrow mapReprProxy = new MapMethod("__repr__", 0) { + @Override public PyObject __call__() { - StringBuilder repr = new StringBuilder("{"); - for (Map.Entry entry : asMap().entrySet()) { - Object jkey = entry.getKey(); - Object jval = entry.getValue(); - repr.append(jkey.toString()); - repr.append(": "); - repr.append(jval == asMap() ? "{...}" : (jval == null ? "None" : jval.toString())); - repr.append(", "); - } - int lastindex = repr.lastIndexOf(", "); - if (lastindex > -1) { - repr.delete(lastindex, lastindex + 2); + ThreadState ts = Py.getThreadState(); + if (!ts.enterRepr(self)) { + return Py.newString("{...}"); + } else { + StringBuilder repr = new StringBuilder("{"); + boolean first = true; + for (Map.Entry entry : asMap().entrySet()) { + if (first) { + first = false; + } else { + repr.append(", "); + } + PyObject key = Py.java2py(entry.getKey()); + repr.append(key.__repr__().toString()); + repr.append(": "); + PyObject value = Py.java2py(entry.getValue()); + repr.append(value.__repr__().toString()); + } + repr.append("}"); + ts.exitRepr(self); + return Py.newString(repr.toString()); } - repr.append("}"); - return new PyString(repr.toString()); } }; private static final PyBuiltinMethodNarrow mapEqProxy = new MapMethod("__eq__", 1) { + @Override public PyObject __call__(PyObject other) { return mapEq(self, other); } }; + private static final PyBuiltinMethodNarrow mapNeProxy = new MapMethod("__ne__", 1) { + + @Override + public PyObject __call__(PyObject other) { + // mapEq may return null if we don't know how to compare to other. + PyBoolean equal = mapEq(self, other); + if (equal != null) { + // implement NOT equal by the inverse of equal + return equal.__not__(); + } + return null; + } + }; private static final PyBuiltinMethodNarrow mapLeProxy = new MapMethod("__le__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other); } }; private static final PyBuiltinMethodNarrow mapGeProxy = new MapMethod("__ge__", 1) { + @Override public PyObject __call__(PyObject other) { return (mapLe(self, other).__not__()).__or__(mapEq(self, other)); } }; private static final PyBuiltinMethodNarrow mapLtProxy = new MapMethod("__lt__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other).__and__(mapEq(self, other).__not__()); } }; private static final PyBuiltinMethodNarrow mapGtProxy = new MapMethod("__gt__", 1) { + @Override public PyObject __call__(PyObject other) { return mapLe(self, other).__not__(); } }; private static final PyBuiltinMethodNarrow mapIterProxy = new MapMethod("__iter__", 0) { + @Override public PyObject __call__() { return new JavaIterator(asMap().keySet()); } }; private static final PyBuiltinMethodNarrow mapContainsProxy = new MapMethod("__contains__", 1) { + @Override public PyObject __call__(PyObject obj) { - Object other = obj.__tojava__(Object.class); - return asMap().containsKey(other) ? Py.True : Py.False; + return asMap().containsKey(tojava(obj)) ? Py.True : Py.False; } }; - // "get" needs to override java.util.Map#get() in its subclasses, too, so this needs to be injected last - // (i.e. when HashMap is loaded not when it is recursively loading its super-type Map) + /* + * "get" needs to override java.util.Map#get() in its subclasses, too, so this needs to be + * injected last (i.e. when HashMap is loaded not when it is recursively loading its super-type + * Map). + */ private static final PyBuiltinMethodNarrow mapGetProxy = new MapMethod("get", 1, 2) { + @Override public PyObject __call__(PyObject key) { return __call__(key, Py.None); @@ -168,66 +264,83 @@ public PyObject __call__(PyObject key) { @Override public PyObject __call__(PyObject key, PyObject _default) { - Object jkey = Py.tojava(key, Object.class); - if (asMap().containsKey(jkey)) { - return Py.java2py(asMap().get(jkey)); + Map map = asMap(); + Object k = tojava(key); + if (map.containsKey(k)) { + return Py.java2py(map.get(k)); } else { return _default; } } }; + private static final PyBuiltinMethodNarrow mapGetItemProxy = new MapMethod("__getitem__", 1) { + @Override public PyObject __call__(PyObject key) { - Object jkey = Py.tojava(key, Object.class); - if (asMap().containsKey(jkey)) { - return Py.java2py(asMap().get(jkey)); - } else { - throw Py.KeyError(key); + Map map = asMap(); + Object k = tojava(key); + if (map.containsKey(k)) { + return Py.java2py(map.get(k)); } + throw Py.KeyError(key); } }; + private static final PyBuiltinMethodNarrow mapPutProxy = new MapMethod("__setitem__", 2) { + @Override public PyObject __call__(PyObject key, PyObject value) { - asMap().put(Py.tojava(key, Object.class), - value == Py.None ? Py.None : Py.tojava(value, Object.class)); - return Py.None; + try { + asMap().put(tojava(key), tojava(value)); + return Py.None; + } catch (NullPointerException npe) { + throw nullException(npe, key, value); + } } }; + private static final PyBuiltinMethodNarrow mapRemoveProxy = new MapMethod("__delitem__", 1) { + @Override public PyObject __call__(PyObject key) { - Object jkey = Py.tojava(key, Object.class); - if (asMap().remove(jkey) == null) { - throw Py.KeyError(key); + Map map = asMap(); + Object k = tojava(key); + if (map.containsKey(k)) { + map.remove(k); + return Py.None; } - return Py.None; + throw Py.KeyError(key); } }; + private static final PyBuiltinMethodNarrow mapIterItemsProxy = new MapMethod("iteritems", 0) { + @Override public PyObject __call__() { - final Iterator> entrySetIterator = asMap().entrySet().iterator(); + final Iterator> entryIterator = asMap().entrySet().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { - if (entrySetIterator.hasNext()) { - Map.Entry nextEntry = entrySetIterator.next(); + if (entryIterator.hasNext()) { + Map.Entry e = entryIterator.next(); // yield a Python tuple object (key, value) - return new PyTuple(Py.java2py(nextEntry.getKey()), - Py.java2py(nextEntry.getValue())); + return new PyTuple(Py.java2py(e.getKey()), Py.java2py(e.getValue())); } return null; } }; } }; + private static final PyBuiltinMethodNarrow mapIterKeysProxy = new MapMethod("iterkeys", 0) { + @Override public PyObject __call__() { final Iterator keyIterator = asMap().keySet().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { if (keyIterator.hasNext()) { @@ -240,11 +353,14 @@ public PyObject __iternext__() { }; } }; + private static final PyBuiltinMethodNarrow mapIterValuesProxy = new MapMethod("itervalues", 0) { + @Override public PyObject __call__() { final Iterator valueIterator = asMap().values().iterator(); return new PyIterator() { + @Override public PyObject __iternext__() { if (valueIterator.hasNext()) { @@ -257,13 +373,17 @@ public PyObject __iternext__() { }; } }; + private static final PyBuiltinMethodNarrow mapHasKeyProxy = new MapMethod("has_key", 1) { + @Override public PyObject __call__(PyObject key) { - return asMap().containsKey(Py.tojava(key, Object.class)) ? Py.True : Py.False; + return asMap().containsKey(tojava(key)) ? Py.True : Py.False; } }; + private static final PyBuiltinMethodNarrow mapKeysProxy = new MapMethod("keys", 0) { + @Override public PyObject __call__() { PyList keys = new PyList(); @@ -273,7 +393,9 @@ public PyObject __call__() { return keys; } }; + private static final PyBuiltinMethod mapValuesProxy = new MapMethod("values", 0) { + @Override public PyObject __call__() { PyList values = new PyList(); @@ -283,24 +405,34 @@ public PyObject __call__() { return values; } }; - private static final PyBuiltinMethodNarrow mapSetDefaultProxy = new MapMethod("setdefault", 1, 2) { - @Override - public PyObject __call__(PyObject key) { - return __call__(key, Py.None); - } - @Override - public PyObject __call__(PyObject key, PyObject _default) { - Object jkey = Py.tojava(key, Object.class); - Object jval = asMap().get(jkey); - if (jval == null) { - asMap().put(jkey, _default == Py.None ? Py.None : Py.tojava(_default, Object.class)); - return _default; - } - return Py.java2py(jval); - } - }; + private static final PyBuiltinMethodNarrow mapSetDefaultProxy = + new MapMethod("setdefault", 1, 2) { + + @Override + public PyObject __call__(PyObject key) { + return __call__(key, Py.None); + } + + @Override + public PyObject __call__(PyObject pykey, PyObject _default) { + Map map = asMap(); + Object key = tojava(pykey); + try { + if (map.containsKey(key)) { + return Py.java2py(map.get(key)); + } else { + map.put(key, tojava(_default)); + return _default; + } + } catch (NullPointerException npe) { + throw nullException(npe, key, _default); + } + } + }; + private static final PyBuiltinMethodNarrow mapPopProxy = new MapMethod("pop", 1, 2) { + @Override public PyObject __call__(PyObject key) { return __call__(key, null); @@ -308,61 +440,70 @@ public PyObject __call__(PyObject key) { @Override public PyObject __call__(PyObject key, PyObject _default) { - Object jkey = Py.tojava(key, Object.class); - if (asMap().containsKey(jkey)) { - PyObject value = Py.java2py(asMap().remove(jkey)); - assert (value != null); - return Py.java2py(value); + Map map = asMap(); + Object k = tojava(key); + if (map.containsKey(k)) { + return Py.java2py(map.remove(k)); + } else if (_default == null) { + throw Py.KeyError(key); } else { - if (_default == null) { - throw Py.KeyError(key); - } return _default; } } }; + private static final PyBuiltinMethodNarrow mapPopItemProxy = new MapMethod("popitem", 0) { + @Override public PyObject __call__() { - if (asMap().size() == 0) { - throw Py.KeyError("popitem(): map is empty"); + Map map = asMap(); + Iterator> entryIterator = map.entrySet().iterator(); + if (entryIterator.hasNext()) { + Map.Entry e = entryIterator.next(); + entryIterator.remove(); + return new PyTuple(Py.java2py(e.getKey()), Py.java2py(e.getValue())); } - Object key = asMap().keySet().toArray()[0]; - Object val = asMap().remove(key); - return Py.java2py(val); + throw Py.KeyError("popitem(): map is empty"); } }; + private static final PyBuiltinMethodNarrow mapItemsProxy = new MapMethod("items", 0) { + @Override public PyObject __call__() { PyList items = new PyList(); for (Map.Entry entry : asMap().entrySet()) { - items.add(new PyTuple(Py.java2py(entry.getKey()), - Py.java2py(entry.getValue()))); + items.add(new PyTuple(Py.java2py(entry.getKey()), Py.java2py(entry.getValue()))); } return items; } }; + private static final PyBuiltinMethodNarrow mapCopyProxy = new MapMethod("copy", 0) { + @Override public PyObject __call__() { - Map jmap = asMap(); - Map jclone; + Map map = asMap(); + Map newMap; + Class> clazz; try { - jclone = (Map) jmap.getClass().newInstance(); - } catch (IllegalAccessException e) { - throw Py.JavaError(e); - } catch (InstantiationException e) { + clazz = (Class>) map.getClass(); + Constructor> ctor = clazz.getDeclaredConstructor(); + newMap = ctor.newInstance(); + for (Map.Entry entry : map.entrySet()) { + newMap.put(entry.getKey(), entry.getValue()); + } + } catch (NullPointerException npe) { + throw nullException(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { throw Py.JavaError(e); } - for (Map.Entry entry : jmap.entrySet()) { - jclone.put(entry.getKey(), entry.getValue()); - } - return Py.java2py(jclone); + return Py.java2py(newMap); } }; + private static final PyBuiltinMethodNarrow mapUpdateProxy = new MapMethod("update", 0, 1) { - private Map jmap; @Override public PyObject __call__() { @@ -371,60 +512,62 @@ public PyObject __call__() { @Override public PyObject __call__(PyObject other) { - // `other` is either another dict-like object, or an iterable of key/value pairs (as tuples - // or other iterables of length two) - return __call__(new PyObject[]{other}, new String[]{}); + /* + * `other` is either another dict-like object, or an iterable of key/value pairs (as + * tuples or other iterables of length two) + */ + return __call__(new PyObject[] {other}, new String[] {}); } @Override public PyObject __call__(PyObject[] args, String[] keywords) { - if ((args.length - keywords.length) != 1) { - throw info.unexpectedCall(args.length, false); + // Adapted from PyDictionary#update + int nargs = args.length - keywords.length; + if (nargs > 1) { + throw PyBuiltinCallable.DefaultInfo.unexpectedCall(nargs, false, "update", 0, 1); } - jmap = asMap(); - PyObject other = args[0]; - // update with entries from `other` (adapted from their equivalent in PyDictionary#update) - Object proxy = other.getJavaProxy(); - if (proxy instanceof Map) { - merge((Map) proxy); - } else if (other.__findattr__("keys") != null) { - merge(other); - } else { - mergeFromSeq(other); - } - // update with entries from keyword arguments - for (int i = 0; i < keywords.length; i++) { - String jkey = keywords[i]; - PyObject value = args[1 + i]; - jmap.put(jkey, Py.tojava(value, Object.class)); + Map map = asMap(); + try { + if (nargs == 1) { + PyObject other = args[0]; + Object proxy = other.getJavaProxy(); + if (proxy instanceof Map) { + // other proxies a Java container: take contents verbatim. + map.putAll((Map) proxy); + } else if (other instanceof PyDictionary) { + // keys and values must be converted from Python to Java equivalents. + mergeFromSeq(map, other.invoke("items")); + } else if (other instanceof PyStringMap) { + // keys and values must be converted from Python to Java equivalents. + mergeFromKeys(map, other, ((PyStringMap) other).keys()); + } else if (other.__findattr__("keys") != null) { + // This is a dict-like object but addressed by looking up the keys. + mergeFromKeys(map, other, other.invoke("keys")); + } else { + // This should be a sequence of tuples (each an entry). + mergeFromSeq(map, other); + } + } + // update with entries from keyword arguments + for (int i = 0; i < keywords.length; i++) { + String k = keywords[i]; + Object v = tojava(args[nargs + i]); + map.put(k, v); + } + } catch (NullPointerException npe) { + throw nullException(); } return Py.None; } - private void merge(Map other) { - for (Map.Entry entry : other.entrySet()) { - jmap.put(entry.getKey(), entry.getValue()); - } - } - - private void merge(PyObject other) { - if (other instanceof PyDictionary) { - jmap.putAll(((PyDictionary) other).getMap()); - } else if (other instanceof PyStringMap) { - mergeFromKeys(other, ((PyStringMap) other).keys()); - } else { - mergeFromKeys(other, other.invoke("keys")); - } - } - - private void mergeFromKeys(PyObject other, PyObject keys) { + private void mergeFromKeys(Map map, PyObject other, PyObject keys) { for (PyObject key : keys.asIterable()) { - jmap.put(Py.tojava(key, Object.class), - Py.tojava(other.__getitem__(key), Object.class)); + Object value = tojava(other.__getitem__(key)); + map.put(tojava(key), value); } } - private void mergeFromSeq(PyObject other) { + private void mergeFromSeq(Map map, PyObject other) { PyObject pairs = other.__iter__(); PyObject pair; @@ -433,47 +576,56 @@ private void mergeFromSeq(PyObject other) { pair = PySequence.fastSequence(pair, ""); } catch (PyException pye) { if (pye.match(Py.TypeError)) { - throw Py.TypeError(String.format("cannot convert dictionary update sequence " - + "element #%d to a sequence", i)); + throw Py.TypeError(String.format(ERR_SEQ, i)); } throw pye; } int n; if ((n = pair.__len__()) != 2) { - throw Py.ValueError(String.format("dictionary update sequence element #%d " - + "has length %d; 2 is required", i, n)); + throw Py.ValueError(String.format(ERR_LENGTH, i, n)); } - jmap.put(Py.tojava(pair.__getitem__(0), Object.class), - Py.tojava(pair.__getitem__(1), Object.class)); + map.put(tojava(pair.__getitem__(0)), tojava(pair.__getitem__(1))); } } + + private static final String ERR_SEQ = + "cannot convert dictionary update element #%d to a sequence"; + private static final String ERR_LENGTH = + "dictionary update sequence element #%d has length %d; 2 is required"; }; - private static final PyBuiltinClassMethodNarrow mapFromKeysProxy = new MapClassMethod("fromkeys", 1, 2) { - @Override - public PyObject __call__(PyObject keys) { - return __call__(keys, null); - } - @Override - public PyObject __call__(PyObject keys, PyObject _default) { - Object defobj = _default == null ? Py.None : Py.tojava(_default, Object.class); - Class theClass = asClass(); - try { - // always injected to java.util.Map, so we know the class object we get from asClass is subtype of java.util.Map - Map theMap = (Map) theClass.newInstance(); - for (PyObject key : keys.asIterable()) { - theMap.put(Py.tojava(key, Object.class), defobj); + private static final PyBuiltinClassMethodNarrow mapFromKeysProxy = + new MapClassMethod("fromkeys", 1, 2) { + + @Override + public PyObject __call__(PyObject keys) { + return __call__(keys, null); } - return Py.java2py(theMap); - } catch (InstantiationException e) { - throw Py.JavaError(e); - } catch (IllegalAccessException e) { - throw Py.JavaError(e); - } - } - }; + + @Override + public PyObject __call__(PyObject keys, PyObject _default) { + Object defobj = tojava(_default); + Class> clazz; + try { + clazz = (Class>) asClass(); + Constructor> ctor = + clazz.getDeclaredConstructor(); + Map theMap = ctor.newInstance(); + for (PyObject key : keys.asIterable()) { + theMap.put(tojava(key), defobj); + } + return Py.java2py(theMap); + } catch (NullPointerException npe) { + throw nullException(); + } catch (ReflectiveOperationException | SecurityException + | IllegalArgumentException e) { + throw Py.JavaError(e); + } + } + }; static PyBuiltinMethod[] getProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ mapLenProxy, // map IterProxy can conflict with Iterable.class; @@ -481,6 +633,7 @@ static PyBuiltinMethod[] getProxyMethods() { mapIterProxy, mapReprProxy, mapEqProxy, + mapNeProxy, mapLeProxy, mapLtProxy, mapGeProxy, @@ -503,6 +656,7 @@ static PyBuiltinMethod[] getProxyMethods() { mapFromKeysProxy // class method }; + //@formatter:on } static PyBuiltinMethod[] getPostProxyMethods() { diff --git a/src/org/python/core/JavaProxySet.java b/src/org/python/core/JavaProxySet.java index 866fedfdb..7358d80a9 100644 --- a/src/org/python/core/JavaProxySet.java +++ b/src/org/python/core/JavaProxySet.java @@ -40,29 +40,44 @@ protected PyObject makePySet(Set newSet) { return newPySet; } - public boolean isEqual(PyObject other) { - Set selfSet = asSet(); - Object oj = other.getJavaProxy(); - if (oj != null && oj instanceof Set) { - @SuppressWarnings("unchecked") - Set otherSet = (Set) oj; - if (selfSet.size() != otherSet.size()) { - return false; - } - return selfSet.containsAll(otherSet); - } else if (isPySet(other)) { - Set otherPySet = ((BaseSet) other).getSet(); + /** + * Compares this object with other to check for equality. Used to implement __eq __ and + * __ne__. May return null if the other object cannot be compared i.e. is not a Python or + * Java set. + * + * @param other The object to compare to this + * @return true is equal, false if not equal and null if we can't compare + */ + protected PyBoolean isEqual(PyObject other) { + if (isPySet(other)) { + // Being compared to a Python set + final Set otherPySet = ((BaseSet) other).getSet(); + final Set selfSet = asSet(); if (selfSet.size() != otherPySet.size()) { - return false; + // Sets are different sizes therefore not equal + return Py.False; } - for (PyObject pyobj : otherPySet) { - if (!selfSet.contains(pyobj.__tojava__(Object.class))) { - return false; + // Do element by element comparison, if any elements are not contained return false + for (Object obj : selfSet) { + if (!otherPySet.contains(Py.java2py(obj))) { + return Py.False; } } - return true; + // All elements are equal so the sets are equal + return Py.True; + } else { + // Being compared to something that is not a Python set + final Object oj = other.getJavaProxy(); + if (oj instanceof Set) { + // Being compared to Java Set convert to Python set and call recursively + final PySet otherPySet = new PySet(Py.javas2pys(((Set) oj).toArray())); + return isEqual(otherPySet); + } else { + // other is not a Python or Java set, so we don't know if + // were equal therefore return null + return null; + } } - return false; } public boolean isSuperset(PyObject other) { @@ -149,6 +164,7 @@ protected Set symDiff(Collection other) { symDiff.removeAll(intersection); return symDiff; } + protected void symDiffUpdate(Collection other) { Set selfSet = asSet(); Set intersection = new HashSet<>(selfSet); @@ -160,28 +176,34 @@ protected void symDiffUpdate(Collection other) { @Untraversable private static class SetMethodVarargs extends SetMethod { + protected SetMethodVarargs(String name) { super(name, 0, -1); } + @Override public PyObject __call__() { return __call__(Py.EmptyObjects); } + @Override public PyObject __call__(PyObject obj) { - return __call__(new PyObject[]{obj}); + return __call__(new PyObject[] {obj}); } + @Override public PyObject __call__(PyObject obj1, PyObject obj2) { - return __call__(new PyObject[]{obj1, obj2}); + return __call__(new PyObject[] {obj1, obj2}); } + @Override public PyObject __call__(PyObject obj1, PyObject obj2, PyObject obj3) { - return __call__(new PyObject[]{obj1, obj2, obj3}); + return __call__(new PyObject[] {obj1, obj2, obj3}); } + @Override public PyObject __call__(PyObject obj1, PyObject obj2, PyObject obj3, PyObject obj4) { - return __call__(new PyObject[]{obj1, obj2, obj3, obj4}); + return __call__(new PyObject[] {obj1, obj2, obj3, obj4}); } } @@ -193,7 +215,7 @@ private static boolean isPySet(PyObject obj) { private static Collection getJavaSet(PyObject self, String op, PyObject obj) { Collection items; if (isPySet(obj)) { - Set otherPySet = ((BaseSet)obj).getSet(); + Set otherPySet = ((BaseSet) obj).getSet(); items = new ArrayList<>(otherPySet.size()); for (PyObject pyobj : otherPySet) { items.add(pyobj.__tojava__(Object.class)); @@ -205,9 +227,9 @@ private static Collection getJavaSet(PyObject self, String op, PyObject Set jSet = (Set) oj; items = jSet; } else { - throw Py.TypeError(String.format( - "unsupported operand type(s) for %s: '%.200s' and '%.200s'", - op, self.getType().fastGetName(), obj.getType().fastGetName())); + throw Py.TypeError( + String.format("unsupported operand type(s) for %s: '%.200s' and '%.200s'", + op, self.getType().fastGetName(), obj.getType().fastGetName())); } } return items; @@ -223,7 +245,7 @@ private static Collection getJavaCollection(PyObject obj) { items = jCollection; } else if (oj instanceof Iterable) { items = new HashSet<>(); - for (Object item: (Iterable) oj) { + for (Object item : (Iterable) oj) { items.add(item); } } else { @@ -278,21 +300,37 @@ private static Collection getCombinedJavaCollections(PyObject[] objs) { } private static final SetMethod cmpProxy = new SetMethod("__cmp__", 1) { + @Override public PyObject __call__(PyObject value) { throw Py.TypeError("cannot compare sets using cmp()"); } }; private static final SetMethod eqProxy = new SetMethod("__eq__", 1) { + + @Override + public PyObject __call__(PyObject other) { + return isEqual(other); + } + }; + private static final SetMethod neProxy = new SetMethod("__ne__", 1) { + @Override public PyObject __call__(PyObject other) { - return Py.newBoolean(isEqual(other)); + // isEqual may return null if we don't know how to compare to other. + PyBoolean equal = isEqual(other); + if (equal != null) { + // implement NOT equal by the inverse of equal + return isEqual(other).__not__(); + } + return null; } }; private static final SetMethod ltProxy = new SetMethod("__lt__", 1) { + @Override public PyObject __call__(PyObject other) { - return Py.newBoolean(!isEqual(other) && isSubset(other)); + return isEqual(other).__not__().__and__(Py.newBoolean(isSubset(other))); } }; @@ -325,35 +363,42 @@ public PyObject __call__(PyObject other) { } private static final SetMethod gtProxy = new SetMethod("__gt__", 1) { + @Override public PyObject __call__(PyObject other) { - return Py.newBoolean(!isEqual(other) && isSuperset(other)); + return isEqual(other).__not__().__and__(Py.newBoolean(isSuperset(other))); } }; private static final SetMethod isDisjointProxy = new SetMethod("isdisjoint", 1) { + @Override public PyObject __call__(PyObject other) { - return Py.newBoolean(intersect(new Collection[]{getJavaCollection(other)}).size() == 0); + Collection[] otherJava = new Collection[] {getJavaCollection(other)}; + return Py.newBoolean(intersect(otherJava).size() == 0); } }; private static final SetMethod differenceProxy = new SetMethodVarargs("difference") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(difference(getCombinedJavaCollections(others))); } }; - private static final SetMethod differenceUpdateProxy = new SetMethodVarargs("difference_update") { - @Override - public PyObject __call__(PyObject[] others) { - differenceUpdate(getCombinedJavaCollections(others)); - return Py.None; - } - }; + private static final SetMethod differenceUpdateProxy = + new SetMethodVarargs("difference_update") { + + @Override + public PyObject __call__(PyObject[] others) { + differenceUpdate(getCombinedJavaCollections(others)); + return Py.None; + } + }; private static final SetMethod subProxy = new SetMethod("__sub__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(difference(getJavaSet(self, "-", other))); @@ -361,6 +406,7 @@ public PyObject __call__(PyObject other) { }; private static final SetMethod isubProxy = new SetMethod("__isub__", 1) { + @Override public PyObject __call__(PyObject other) { differenceUpdate(getJavaSet(self, "-=", other)); @@ -369,51 +415,60 @@ public PyObject __call__(PyObject other) { }; private static final SetMethod intersectionProxy = new SetMethodVarargs("intersection") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(intersect(getJavaCollections(others))); } }; - private static final SetMethod intersectionUpdateProxy = new SetMethodVarargs("intersection_update") { - @Override - public PyObject __call__(PyObject[] others) { - intersectUpdate(getJavaCollections(others)); - return Py.None; - } - }; + private static final SetMethod intersectionUpdateProxy = + new SetMethodVarargs("intersection_update") { + + @Override + public PyObject __call__(PyObject[] others) { + intersectUpdate(getJavaCollections(others)); + return Py.None; + } + }; private static final SetMethod andProxy = new SetMethod("__and__", 1) { + @Override public PyObject __call__(PyObject other) { - return makePySet(intersect(new Collection[]{getJavaSet(self, "&", other)})); + return makePySet(intersect(new Collection[] {getJavaSet(self, "&", other)})); } }; private static final SetMethod iandProxy = new SetMethod("__iand__", 1) { + @Override public PyObject __call__(PyObject other) { - intersectUpdate(new Collection[]{getJavaSet(self, "&=", other)}); + intersectUpdate(new Collection[] {getJavaSet(self, "&=", other)}); return self; } }; private static final SetMethod symDiffProxy = new SetMethod("symmetric_difference", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(symDiff(getJavaCollection(other))); } }; - private static final SetMethod symDiffUpdateProxy = new SetMethod("symmetric_difference_update", 1) { - @Override - public PyObject __call__(PyObject other) { - symDiffUpdate(getJavaCollection(other)); - return Py.None; - } - }; + private static final SetMethod symDiffUpdateProxy = + new SetMethod("symmetric_difference_update", 1) { + + @Override + public PyObject __call__(PyObject other) { + symDiffUpdate(getJavaCollection(other)); + return Py.None; + } + }; private static final SetMethod xorProxy = new SetMethod("__xor__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(symDiff(getJavaSet(self, "^", other))); @@ -421,6 +476,7 @@ public PyObject __call__(PyObject other) { }; private static final SetMethod ixorProxy = new SetMethod("__ixor__", 1) { + @Override public PyObject __call__(PyObject other) { symDiffUpdate(getJavaSet(self, "^=", other)); @@ -429,6 +485,7 @@ public PyObject __call__(PyObject other) { }; private static final SetMethod unionProxy = new SetMethodVarargs("union") { + @Override public PyObject __call__(PyObject[] others) { return makePySet(union(getCombinedJavaCollections(others))); @@ -436,6 +493,7 @@ public PyObject __call__(PyObject[] others) { }; private static final SetMethod updateProxy = new SetMethodVarargs("update") { + @Override public PyObject __call__(PyObject[] others) { update(getCombinedJavaCollections(others)); @@ -444,6 +502,7 @@ public PyObject __call__(PyObject[] others) { }; private static final SetMethod orProxy = new SetMethod("__or__", 1) { + @Override public PyObject __call__(PyObject other) { return makePySet(union(getJavaSet(self, "|", other))); @@ -451,6 +510,7 @@ public PyObject __call__(PyObject other) { }; private static final SetMethod iorProxy = new SetMethod("__ior__", 1) { + @Override public PyObject __call__(PyObject other) { update(getJavaSet(self, "|=", other)); @@ -460,9 +520,11 @@ public PyObject __call__(PyObject other) { @Untraversable private static class CopyMethod extends SetMethod { + protected CopyMethod(String name) { super(name, 0); } + @Override public PyObject __call__() { return makePySet(asSet()); @@ -470,6 +532,7 @@ public PyObject __call__() { } private static final SetMethod deepcopyOverrideProxy = new SetMethod("__deepcopy__", 1) { + @Override public PyObject __call__(PyObject memo) { Set newSet = new HashSet<>(); @@ -483,6 +546,7 @@ public PyObject __call__(PyObject memo) { }; private static final SetMethod reduceProxy = new SetMethod("__reduce__", 0) { + @Override public PyObject __call__() { PyObject args = new PyTuple(new PyList(new JavaIterator(asSet()))); @@ -495,20 +559,24 @@ public PyObject __call__() { }; private static final SetMethod containsProxy = new SetMethod("__contains__", 1) { + @Override public PyObject __call__(PyObject value) { return Py.newBoolean(asSet().contains(value.__tojava__(Object.class))); } }; private static final SetMethod hashProxy = new SetMethod("__hash__", 0) { + // in general, we don't know if this is really true or not @Override public PyObject __call__(PyObject value) { - throw Py.TypeError(String.format("unhashable type: '%.200s'", self.getType().fastGetName())); + throw Py.TypeError( + String.format("unhashable type: '%.200s'", self.getType().fastGetName())); } }; private static final SetMethod discardProxy = new SetMethod("discard", 1) { + @Override public PyObject __call__(PyObject value) { asSet().remove(value.__tojava__(Object.class)); @@ -516,6 +584,7 @@ public PyObject __call__(PyObject value) { } }; private static final SetMethod popProxy = new SetMethod("pop", 0) { + @Override public PyObject __call__() { Set selfSet = asSet(); @@ -535,6 +604,7 @@ public PyObject __call__() { } }; private static final SetMethod removeOverrideProxy = new SetMethod("remove", 1) { + @Override public PyObject __call__(PyObject value) { boolean removed = asSet().remove(value.__tojava__(Object.class)); @@ -546,9 +616,11 @@ public PyObject __call__(PyObject value) { }; static PyBuiltinMethod[] getProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ cmpProxy, eqProxy, + neProxy, ltProxy, new IsSubsetMethod("__le__"), new IsSubsetMethod("issubset"), @@ -587,13 +659,16 @@ static PyBuiltinMethod[] getProxyMethods() { discardProxy, popProxy }; + //@formatter:on } static PyBuiltinMethod[] getPostProxyMethods() { + //@formatter:off return new PyBuiltinMethod[]{ deepcopyOverrideProxy, removeOverrideProxy }; + //@formatter:on } } diff --git a/src/org/python/core/JyAttribute.java b/src/org/python/core/JyAttribute.java index 186feff60..a6a48131a 100644 --- a/src/org/python/core/JyAttribute.java +++ b/src/org/python/core/JyAttribute.java @@ -68,10 +68,7 @@ public abstract class JyAttribute implements Serializable { */ public static final byte WEAKREF_PENDING_GET_ATTR = 3; - /** - * Only used internally by - * {@linkorg.python.core.Py#javaPyClass(PyObject, Class)} - */ + /** Only used internally by {@link Py#javaPyClass(PyObject, Class)} */ public static final byte PYCLASS_PY2JY_CACHE_ATTR = 4; /** @@ -94,8 +91,8 @@ public abstract class JyAttribute implements Serializable { private static byte nonBuiltinTransientAttrTypeOffset = 7; /** - * Reserves and returns a new non-transient attr type for custom use. - * + * Reserves and returns a new non-transient attr type for custom use. + * * @return a non-transient attr type for custom use */ public static byte reserveCustomAttrType() { @@ -106,8 +103,8 @@ public static byte reserveCustomAttrType() { } /** - * Reserves and returns a new transient attr type for custom use. - * + * Reserves and returns a new transient attr type for custom use. + * * @return a transient attr type for custom use */ public static byte reserveTransientCustomAttrType() { @@ -128,18 +125,22 @@ protected AttributeLink(byte attr_type, Object value) { this.value = value; } + @Override protected JyAttribute getNext() { return next; } + @Override protected void setNext(JyAttribute next) { this.next = next; } + @Override protected Object getValue() { return value; } + @Override protected void setValue(Object value) { this.value = value; } @@ -154,18 +155,22 @@ protected TransientAttributeLink(byte attr_type, Object value) { this.value = value; } + @Override protected JyAttribute getNext() { return next; } + @Override protected void setNext(JyAttribute next) { this.next = next; } + @Override protected Object getValue() { return value; } + @Override protected void setValue(Object value) { this.value = value; } @@ -230,9 +235,9 @@ public static void debugPrintAttributes(PyObject o, java.io.PrintStream out) { } /** - * Sets the attribute of type {@code attr_type} in {@code ob} to {@code value}. - * If no corresponding attribute exists yet, one is created. If {@value == null}, - * the attribute is removed (if it existed at all). + * Sets the attribute of type {@code attr_type} in {@code ob} to {@code value}. If no + * corresponding attribute exists yet, one is created. If {@code value == null}, the attribute + * is removed (if it existed at all). */ public static void setAttr(PyObject ob, byte attr_type, Object value) { synchronized (ob) { diff --git a/src/org/python/core/Opcode.java b/src/org/python/core/Opcode.java index e82ce8860..1789e4ef9 100644 --- a/src/org/python/core/Opcode.java +++ b/src/org/python/core/Opcode.java @@ -1,172 +1,174 @@ package org.python.core; -// derived from CPython 2.5.2 Include/opcode.h - -public class Opcode { - - public static final int POP_TOP = 1; - public static final int ROT_TWO = 2; - public static final int ROT_THREE = 3; - public static final int DUP_TOP = 4; - public static final int ROT_FOUR = 5; - public static final int NOP = 9; - public static final int UNARY_POSITIVE = 10; - public static final int UNARY_NEGATIVE = 11; - public static final int UNARY_NOT = 12; - public static final int UNARY_CONVERT = 13; - public static final int UNARY_INVERT = 15; - public static final int LIST_APPEND = 18; - public static final int BINARY_POWER = 19; - public static final int BINARY_MULTIPLY = 20; - public static final int BINARY_DIVIDE = 21; - public static final int BINARY_MODULO = 22; - public static final int BINARY_ADD = 23; - public static final int BINARY_SUBTRACT = 24; - public static final int BINARY_SUBSCR = 25; - public static final int BINARY_FLOOR_DIVIDE = 26; - public static final int BINARY_TRUE_DIVIDE = 27; - public static final int INPLACE_FLOOR_DIVIDE = 28; - public static final int INPLACE_TRUE_DIVIDE = 29; - public static final int SLICE = 30; +// derived from CPython 2.7.12 Include/opcode.h + +public interface Opcode { + + /* Instruction opcodes for compiled code */ + + public static final int STOP_CODE = 0; + public static final int POP_TOP = 1; + public static final int ROT_TWO = 2; + public static final int ROT_THREE = 3; + public static final int DUP_TOP = 4; + public static final int ROT_FOUR = 5; + public static final int NOP = 9; + + public static final int UNARY_POSITIVE = 10; + public static final int UNARY_NEGATIVE = 11; + public static final int UNARY_NOT = 12; + public static final int UNARY_CONVERT = 13; + public static final int UNARY_INVERT = 15; + + public static final int BINARY_POWER = 19; + public static final int BINARY_MULTIPLY = 20; + public static final int BINARY_DIVIDE = 21; + public static final int BINARY_MODULO = 22; + public static final int BINARY_ADD = 23; + public static final int BINARY_SUBTRACT = 24; + public static final int BINARY_SUBSCR = 25; + public static final int BINARY_FLOOR_DIVIDE = 26; + public static final int BINARY_TRUE_DIVIDE = 27; + + public static final int INPLACE_FLOOR_DIVIDE = 28; + public static final int INPLACE_TRUE_DIVIDE = 29; + + public static final int SLICE = 30; /* Also uses 31-33 */ - public static final int STORE_SLICE = 40; - /* Also uses 41-43 */ - public static final int DELETE_SLICE = 50; - /* Also uses 51-53 */ - public static final int INPLACE_ADD = 55; - public static final int INPLACE_SUBTRACT = 56; - public static final int INPLACE_MULTIPLY = 57; - public static final int INPLACE_DIVIDE = 58; - public static final int INPLACE_MODULO = 59; - public static final int STORE_SUBSCR = 60; - public static final int DELETE_SUBSCR = 61; - public static final int BINARY_LSHIFT = 62; - public static final int BINARY_RSHIFT = 63; - public static final int BINARY_AND = 64; - public static final int BINARY_XOR = 65; - public static final int BINARY_OR = 66; - public static final int INPLACE_POWER = 67; - public static final int GET_ITER = 68; - public static final int PRINT_EXPR = 70; - public static final int PRINT_ITEM = 71; - public static final int PRINT_NEWLINE = 72; - public static final int PRINT_ITEM_TO = 73; - public static final int PRINT_NEWLINE_TO = 74; - public static final int INPLACE_LSHIFT = 75; - public static final int INPLACE_RSHIFT = 76; - public static final int INPLACE_AND = 77; - public static final int INPLACE_XOR = 78; - public static final int INPLACE_OR = 79; - public static final int BREAK_LOOP = 80; - public static final int WITH_CLEANUP = 81; - public static final int LOAD_LOCALS = 82; - public static final int RETURN_VALUE = 83; - public static final int IMPORT_STAR = 84; - public static final int EXEC_STMT = 85; - public static final int YIELD_VALUE = 86; - public static final int POP_BLOCK = 87; - public static final int END_FINALLY = 88; - public static final int BUILD_CLASS = 89; - public static final int HAVE_ARGUMENT = 90; /* Opcodes from here have an argument: */ - - public static final int STORE_NAME = 90; /* Index in name list */ - - public static final int DELETE_NAME = 91; /* "" */ - - public static final int UNPACK_SEQUENCE = 92; /* Number of sequence items */ - - public static final int FOR_ITER = 93; - public static final int STORE_ATTR = 95; /* Index in name list */ - - public static final int DELETE_ATTR = 96; /* "" */ - - public static final int STORE_GLOBAL = 97; /* "" */ - - public static final int DELETE_GLOBAL = 98; /* "" */ - - public static final int DUP_TOPX = 99; /* number of items to duplicate */ - - public static final int LOAD_CONST = 100; /* Index in const list */ - - public static final int LOAD_NAME = 101; /* Index in name list */ - - public static final int BUILD_TUPLE = 102; /* Number of tuple items */ - - public static final int BUILD_LIST = 103; /* Number of list items */ - - public static final int BUILD_MAP = 104; /* Always zero for now */ - - public static final int LOAD_ATTR = 105; /* Index in name list */ - - public static final int COMPARE_OP = 106; /* Comparison operator */ - - public static final int IMPORT_NAME = 107; /* Index in name list */ - - public static final int IMPORT_FROM = 108; /* Index in name list */ - - public static final int JUMP_FORWARD = 110; /* Number of bytes to skip */ - - public static final int JUMP_IF_FALSE = 111; /* "" */ + public static final int SLICE_1 = 31; + public static final int SLICE_2 = 32; + public static final int SLICE_3 = 33; - public static final int JUMP_IF_TRUE = 112; /* "" */ - - public static final int JUMP_ABSOLUTE = 113; /* Target byte offset from beginning of code */ - - public static final int LOAD_GLOBAL = 116; /* Index in name list */ - - public static final int CONTINUE_LOOP = 119; /* Start of loop (absolute) */ - - public static final int SETUP_LOOP = 120; /* Target address (absolute) */ - - public static final int SETUP_EXCEPT = 121; /* "" */ - - public static final int SETUP_FINALLY = 122; /* "" */ - - public static final int LOAD_FAST = 124; /* Local variable number */ - - public static final int STORE_FAST = 125; /* Local variable number */ - - public static final int DELETE_FAST = 126; /* Local variable number */ + public static final int STORE_SLICE = 40; + /* Also uses 41-43 */ + public static final int STORE_SLICE_1 = 41; + public static final int STORE_SLICE_2 = 42; + public static final int STORE_SLICE_3 = 43; - public static final int RAISE_VARARGS = 130; /* Number of raise arguments (1, 2 or 3) */ + public static final int DELETE_SLICE = 50; + /* Also uses 51-53 */ + public static final int DELETE_SLICE_1 = 51; + public static final int DELETE_SLICE_2 = 52; + public static final int DELETE_SLICE_3 = 53; + + public static final int STORE_MAP = 54; + public static final int INPLACE_ADD = 55; + public static final int INPLACE_SUBTRACT = 56; + public static final int INPLACE_MULTIPLY = 57; + public static final int INPLACE_DIVIDE = 58; + public static final int INPLACE_MODULO = 59; + public static final int STORE_SUBSCR = 60; + public static final int DELETE_SUBSCR = 61; + + public static final int BINARY_LSHIFT = 62; + public static final int BINARY_RSHIFT = 63; + public static final int BINARY_AND = 64; + public static final int BINARY_XOR = 65; + public static final int BINARY_OR = 66; + public static final int INPLACE_POWER = 67; + public static final int GET_ITER = 68; + + public static final int PRINT_EXPR = 70; + public static final int PRINT_ITEM = 71; + public static final int PRINT_NEWLINE = 72; + public static final int PRINT_ITEM_TO = 73; + public static final int PRINT_NEWLINE_TO = 74; + public static final int INPLACE_LSHIFT = 75; + public static final int INPLACE_RSHIFT = 76; + public static final int INPLACE_AND = 77; + public static final int INPLACE_XOR = 78; + public static final int INPLACE_OR = 79; + public static final int BREAK_LOOP = 80; + public static final int WITH_CLEANUP = 81; + public static final int LOAD_LOCALS = 82; + public static final int RETURN_VALUE = 83; + public static final int IMPORT_STAR = 84; + public static final int EXEC_STMT = 85; + public static final int YIELD_VALUE = 86; + public static final int POP_BLOCK = 87; + public static final int END_FINALLY = 88; + public static final int BUILD_CLASS = 89; + + public static final int HAVE_ARGUMENT = 90; /* Opcodes from here have an argument: */ + + public static final int STORE_NAME = 90; /* Index in name list */ + public static final int DELETE_NAME = 91; /* "" */ + public static final int UNPACK_SEQUENCE = 92; /* Number of sequence items */ + public static final int FOR_ITER = 93; + public static final int LIST_APPEND = 94; + + public static final int STORE_ATTR = 95; /* Index in name list */ + public static final int DELETE_ATTR = 96; /* "" */ + public static final int STORE_GLOBAL = 97; /* "" */ + public static final int DELETE_GLOBAL = 98; /* "" */ + public static final int DUP_TOPX = 99; /* number of items to duplicate */ + public static final int LOAD_CONST = 100; /* Index in const list */ + public static final int LOAD_NAME = 101; /* Index in name list */ + public static final int BUILD_TUPLE = 102; /* Number of tuple items */ + public static final int BUILD_LIST = 103; /* Number of list items */ + public static final int BUILD_SET = 104; /* Number of set items */ + public static final int BUILD_MAP = 105; /* Always zero for now */ + public static final int LOAD_ATTR = 106; /* Index in name list */ + public static final int COMPARE_OP = 107; /* Comparison operator */ + public static final int IMPORT_NAME = 108; /* Index in name list */ + public static final int IMPORT_FROM = 109; /* Index in name list */ + + public static final int JUMP_FORWARD = 110; /* Number of bytes to skip */ + public static final int JUMP_IF_FALSE_OR_POP = 111; /* Target byte offset from beginning of code */ + public static final int JUMP_IF_TRUE_OR_POP = 112; /* "" */ + public static final int JUMP_ABSOLUTE = 113; /* "" */ + public static final int POP_JUMP_IF_FALSE = 114; /* "" */ + public static final int POP_JUMP_IF_TRUE = 115; /* "" */ + + public static final int LOAD_GLOBAL = 116; /* Index in name list */ + + public static final int CONTINUE_LOOP = 119; /* Start of loop (absolute) */ + public static final int SETUP_LOOP = 120; /* Target address (relative) */ + public static final int SETUP_EXCEPT = 121; /* "" */ + public static final int SETUP_FINALLY = 122; /* "" */ + + public static final int LOAD_FAST = 124; /* Local variable number */ + public static final int STORE_FAST = 125; /* Local variable number */ + public static final int DELETE_FAST = 126; /* Local variable number */ + + public static final int RAISE_VARARGS = 130; /* Number of raise arguments (1, 2 or 3) */ /* CALL_FUNCTION_XXX opcodes defined below depend on this definition */ + public static final int CALL_FUNCTION = 131; /* #args + (#kwargs<<8) */ + public static final int MAKE_FUNCTION = 132; /* #defaults */ + public static final int BUILD_SLICE = 133; /* Number of items */ - public static final int CALL_FUNCTION = 131; /* #args + (#kwargs<<8) */ - - public static final int MAKE_FUNCTION = 132; /* #defaults */ - - public static final int BUILD_SLICE = 133; /* Number of items */ - - public static final int MAKE_CLOSURE = 134; /* #free vars */ - - public static final int LOAD_CLOSURE = 135; /* Load free variable from closure */ - - public static final int LOAD_DEREF = 136; /* Load and dereference from closure cell */ - - public static final int STORE_DEREF = 137; /* Store into cell */ + public static final int MAKE_CLOSURE = 134; /* #free vars */ + public static final int LOAD_CLOSURE = 135; /* Load free variable from closure */ + public static final int LOAD_DEREF = 136; /* Load and dereference from closure cell */ + public static final int STORE_DEREF = 137; /* Store into cell */ /* The next 3 opcodes must be contiguous and satisfy - (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1 */ - public static final int CALL_FUNCTION_VAR = 140; /* #args + (#kwargs<<8) */ - - public static final int CALL_FUNCTION_KW = 141; /* #args + (#kwargs<<8) */ + (CALL_FUNCTION_VAR - CALL_FUNCTION) & 3 == 1 */ + public static final int CALL_FUNCTION_VAR = 140; /* #args + (#kwargs<<8) */ + public static final int CALL_FUNCTION_KW = 141; /* #args + (#kwargs<<8) */ + public static final int CALL_FUNCTION_VAR_KW = 142; /* #args + (#kwargs<<8) */ - public static final int CALL_FUNCTION_VAR_KW = 142; /* #args + (#kwargs<<8) */ + public static final int SETUP_WITH = 143; /* Support for opargs more than 16 bits long */ - public static final int EXTENDED_ARG = 143; + public static final int EXTENDED_ARG = 145; + + public static final int SET_ADD = 146; + public static final int MAP_ADD = 147; + // comparison opcodes (on the oparg), just put in this class too - public static final int PyCmp_LT = 0; - public static final int PyCmp_LE = 1; - public static final int PyCmp_EQ = 2; - public static final int PyCmp_NE = 3; - public static final int PyCmp_GT = 4; - public static final int PyCmp_GE = 5; - public static final int PyCmp_IN = 6; - public static final int PyCmp_NOT_IN = 7; - public static final int PyCmp_IS = 8; - public static final int PyCmp_IS_NOT = 9; + public static final int PyCmp_LT = 0; + public static final int PyCmp_LE = 1; + public static final int PyCmp_EQ = 2; + public static final int PyCmp_NE = 3; + public static final int PyCmp_GT = 4; + public static final int PyCmp_GE = 5; + public static final int PyCmp_IN = 6; + public static final int PyCmp_NOT_IN = 7; + public static final int PyCmp_IS = 8; + public static final int PyCmp_IS_NOT = 9; public static final int PyCmp_EXC_MATCH = 10; + public static final int PyCmp_BAD = 11; } diff --git a/src/org/python/core/Options.java b/src/org/python/core/Options.java index 690671e72..285b7f23f 100644 --- a/src/org/python/core/Options.java +++ b/src/org/python/core/Options.java @@ -1,102 +1,150 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.core; +import static org.python.core.RegistryKey.*; + +import java.util.logging.Level; + /** - * A class with static fields for each of the settable options. The options from - * registry and command line is copied into the fields here and the rest of - * Jython checks these fields. + * A class with static fields for each of the settable options. The options from registry and + * command line is copied into the fields here and the rest of Jython checks these fields. */ public class Options { // Jython options. Some of these can be set from the command line // options, but all can be controlled through the Jython registry /** - * when an exception occurs in Java code, and it is not caught, should the - * interpreter print out the Java exception in the traceback? + * when an exception occurs in Java code, and it is not caught, should the interpreter print out + * the Java exception in the traceback? */ public static boolean showJavaExceptions = false; /** - * If true, exceptions raised from Python code will include a Java stack - * trace in addition to the Python traceback. This can slow raising - * considerably. + * If true, exceptions raised from Python code will include a Java stack trace in addition to + * the Python traceback. This can slow raising considerably. + * + * @see org.python.core.RegistryKey#PYTHON_OPTIONS_INCLUDE_JAVA_STACK_IN_EXCEPTIONS */ public static boolean includeJavaStackInExceptions = true; /** - * When true, python exception raised in overridden methods will be shown on - * stderr. This option is remarkably useful when python is used for - * implementing CORBA server. Some CORBA servers will turn python exception - * (say a NameError) into an anonymous user exception without any + * When true, python exception raised in overridden methods will be shown on stderr. This option + * is remarkably useful when python is used for implementing CORBA server. Some CORBA servers + * will turn python exception (say a NameError) into an anonymous user exception without any * stacktrace. Setting this option will show the stacktrace. + * + * @see org.python.core.RegistryKey#PYTHON_OPTIONS_SHOW_PYTHON_PROXY_EXCEPTIONS */ public static boolean showPythonProxyExceptions = false; /** - * If true, Jython respects Java the accessibility flag for fields, - * methods, and constructors. This means you can only access public members. - * Set this to false to access all members by toggling the accessible flag - * on the member. + * If true, Jython respects Java the accessibility flag for fields, methods, and constructors. + * This means you can only access public members. Set this to false to access all members by + * toggling the accessible flag on the member. + * + * @see org.python.core.RegistryKey#PYTHON_SECURITY_RESPECT_JAVA_ACCESSIBILITY */ public static boolean respectJavaAccessibility = true; /** - * When false the site.py will not be imported. This is only - * honored by the command line main class. + * When {@code false} the site.py will not be imported. This may be set by the + * command line main class ({@code -S} option) or from the registry and is checked in + * {@link org.python.util.PythonInterpreter}. + * + * @see #no_site + * @see org.python.core.RegistryKey#PYTHON_IMPORT_SITE */ public static boolean importSite = true; /** - * Set verbosity to Py.ERROR, Py.WARNING, Py.MESSAGE, Py.COMMENT, or - * Py.DEBUG for varying levels of informative messages from Jython. Normally - * this option is set from the command line. + * When {@code true} the {@code site.py} was not imported. This is may be set by the command + * line main class ({@code -S} option) or from the registry. However, in Jython 2, + * {@code no_site} is simply the opposite of {@link #importSite}, as the interpreter starts up, + * provided for compatibility with the standard Python {@code sys.flags}. Actual control over + * the import of the site module in Jython 2, when necessary from Java, is accomplished through + * {@link #importSite}. + */ + /* + * This should be the standard Python way to control import of the site module. Unfortunately, + * importSite is quite old and we cannot rule out use by applications. Correct in Jython 3. + */ + public static boolean no_site = false; + + /** + * Verbosity of informative messages from Jython, retained as a field for reasons of + * backward-compatibility. Normally this option should be allowed to find its value indirectly + * through {@code java.util.logging}, as adjusted by the command line {@code -v} option. + * + * @deprecated Use {@link Py#getLoggingLevel()}, + * {@link Py#setLoggingLevel(java.util.logging.Level)}, or {@code java.util.logging} + * preferences to configure logging levels. */ - public static int verbose = Py.MESSAGE; + @Deprecated + public static int verbose = PrePy.verbosityFromLevel(PrePy.getLoggingLevel()); /** - * A directory where the dynamically generated classes are written. Nothing is - * ever read from here, it is only for debugging purposes. + * Set by the {@code -i} option to the interpreter command, to ask for an interactive session to + * start after the script ends. It also allows certain streams to be considered interactive when + * {@code isatty} is not available. + */ + public static boolean interactive = false; + + /** + * When a script given on the command line finishes, start an interactive interpreter. It is set + * {@code true} by the {@code -i} option on the command-line, or programmatically from the + * script, and reset to {@code false} just before the interactive session starts. (This session + * only actually starts if the console is interactive.) + */ + public static boolean inspect = false; + + /** + * A directory where the dynamically generated classes are written. Nothing is ever read from + * here, it is only for debugging purposes. */ public static String proxyDebugDirectory; /** - * If true, Jython will use the first module found on sys.path where java - * File.isFile() returns true. Setting this to true have no effect on - * unix-type filesystems. On Windows/HFS+ systems setting it to true will - * enable Jython-2.0 behaviour. + * If true, Jython will use the first module found on sys.path where java File.isFile() returns + * true. Setting this to true have no effect on unix-type filesystems. On Windows/HFS+ systems + * setting it to true will enable Jython-2.0 behaviour. + * + * @see org.python.core.RegistryKey#PYTHON_OPTIONS_CASE_OK */ public static boolean caseok = false; /** - * If true, enable truedivision for the '/' operator. + * If true, enable true division for the '/' operator. + * + * @see org.python.core.RegistryKey#PYTHON_OPTIONS_Q_NEW */ public static boolean Qnew = false; - /** Force stdin, stdout and stderr to be unbuffered, and opened in - * binary mode */ + /** Force stdin, stdout and stderr to be unbuffered, and opened in binary mode. */ public static boolean unbuffered = false; /** Whether -3 (py3k warnings) was enabled via the command line. */ public static boolean py3k_warning = false; - + /** Whether -B (don't write bytecode on import) was enabled via the command line. */ public static boolean dont_write_bytecode = false; /** Whether -E (ignore environment) was enabled via the command line. */ public static boolean ignore_environment = false; - //XXX: place holder, not implemented yet. + /** + * Whether -s (don't add user site directory to {@code sys.path}) was on the command line. The + * implementation is mostly in the {@code site} module. + */ public static boolean no_user_site = false; - //XXX: place holder, not implemented yet. - public static boolean no_site = false; - - //XXX: place holder + // XXX: place holder public static int bytes_warning = 0; - // Corresponds to -O (Python bytecode optimization), -OO (remove docstrings) - // flags in CPython; it's not clear how Jython should expose its optimization, - // but this is user visible as of 2.7. + /** + * Corresponds to -O (Python bytecode optimization), -OO (remove docstrings) flags in CPython. + * Jython processes the option and makes it visible as of 2.7, but there is no change of + * behaviour in the current version. + */ public static int optimize = 0; /** @@ -110,23 +158,22 @@ public class Options { public static int division_warning = 0; /** - * Cache spec for the SRE_STATE code point cache. The value maps to the - * CacheBuilderSpec string and affects how the SRE_STATE cache will behave/evict - * cached PyString -> int[] code points. + * Cache spec for the SRE_STATE code point cache. The value maps to the CacheBuilderSpec string + * and affects how the SRE_STATE cache will behave/evict cached {@code PyString -> int[]} code + * points. */ - public static final String sreCacheSpecDefault = "weakKeys,concurrencyLevel=4,maximumWeight=2621440,expireAfterAccess=30s"; + public static final String sreCacheSpecDefault = + "weakKeys,concurrencyLevel=4,maximumWeight=2621440,expireAfterAccess=30s"; public static String sreCacheSpec = sreCacheSpecDefault; // // ####### END OF OPTIONS // - private Options() { - ; - } + private Options() {} private static boolean getBooleanOption(String name, boolean defaultValue) { - String prop = PySystemState.registry.getProperty("python." + name); + String prop = PySystemState.registry.getProperty(name); if (prop == null) { return defaultValue; } @@ -134,74 +181,107 @@ private static boolean getBooleanOption(String name, boolean defaultValue) { } private static String getStringOption(String name, String defaultValue) { - String prop = PySystemState.registry.getProperty("python." + name); + String prop = PySystemState.registry.getProperty(name); if (prop == null) { return defaultValue; } return prop; } + /** Initialize the static fields from the registry options. */ + public static void setFromRegistry() { + + showJavaExceptions = + getBooleanOption(PYTHON_OPTIONS_SHOW_JAVA_EXCEPTIONS, showJavaExceptions); + includeJavaStackInExceptions = getBooleanOption( + PYTHON_OPTIONS_INCLUDE_JAVA_STACK_IN_EXCEPTIONS, includeJavaStackInExceptions); + showPythonProxyExceptions = getBooleanOption(PYTHON_OPTIONS_SHOW_PYTHON_PROXY_EXCEPTIONS, + showPythonProxyExceptions); + respectJavaAccessibility = getBooleanOption(PYTHON_SECURITY_RESPECT_JAVA_ACCESSIBILITY, + respectJavaAccessibility); + proxyDebugDirectory = + getStringOption(PYTHON_OPTIONS_PROXY_DEBUG_DIRECTORY, proxyDebugDirectory); + + // Legacy python.verbose if used may countermand logging.properties::org.python.level + setLoggingFromRegistry(); + + caseok = getBooleanOption(PYTHON_OPTIONS_CASE_OK, caseok); + Qnew = getBooleanOption(PYTHON_OPTIONS_Q_NEW, Qnew); + + setDivisionWarningFromRegistry(); + + sreCacheSpec = getStringOption(PYTHON_SRE_CACHESPEC, sreCacheSpec); + inspect |= getStringOption(PYTHON_INSPECT, "").length() > 0; + importSite = getBooleanOption(PYTHON_IMPORT_SITE, importSite); + no_site = !importSite; + } + /** - * Initialize the static fields from the registry options. + * Set the logging level from {@link RegistryKey#PYTHON_VERBOSE}. We recognise the traditional + * Jython names and those used by {@code java.util.logging}. If that key is present in the + * Jython registry it will determine the level or the logger named "org.python". */ - public static void setFromRegistry() { - // Set the more unusual options - Options.showJavaExceptions = getBooleanOption( - "options.showJavaExceptions", Options.showJavaExceptions); - - Options.includeJavaStackInExceptions = getBooleanOption( - "options.includeJavaStackInExceptions", Options.includeJavaStackInExceptions); - - Options.showPythonProxyExceptions = getBooleanOption( - "options.showPythonProxyExceptions", - Options.showPythonProxyExceptions); - - Options.respectJavaAccessibility = getBooleanOption( - "security.respectJavaAccessibility", - Options.respectJavaAccessibility); - - Options.proxyDebugDirectory = getStringOption( - "options.proxyDebugDirectory", Options.proxyDebugDirectory); - - // verbosity is more complicated: - String prop = PySystemState.registry.getProperty("python.verbose"); - if (prop != null) { - if (prop.equalsIgnoreCase("error")) { - Options.verbose = Py.ERROR; - } else if (prop.equalsIgnoreCase("warning")) { - Options.verbose = Py.WARNING; - } else if (prop.equalsIgnoreCase("message")) { - Options.verbose = Py.MESSAGE; - } else if (prop.equalsIgnoreCase("comment")) { - Options.verbose = Py.COMMENT; - } else if (prop.equalsIgnoreCase("debug")) { - Options.verbose = Py.DEBUG; - } else { - throw Py.ValueError("Illegal verbose option setting: '" + prop - + "'"); - } + private static void setLoggingFromRegistry() { + String prop; + switch ((prop = getStringOption(PYTHON_VERBOSE, "")).toLowerCase()) { + case "": // Leave it as it is. + break; + case "off": + PrePy.setLoggingLevel(Level.OFF); + break; + case "error": + case "severe": + PrePy.setLoggingLevel(Level.SEVERE); + break; + case "warning": + case "warn": + PrePy.setLoggingLevel(Level.WARNING); + break; + case "message": + case "info": + PrePy.setLoggingLevel(Level.INFO); + break; + case "comment": + case "config": + PrePy.setLoggingLevel(Level.CONFIG); + break; + case "debug": + case "fine": + PrePy.setLoggingLevel(Level.FINE); + break; + case "finer": + PrePy.setLoggingLevel(Level.FINER); + break; + case "finest": + PrePy.setLoggingLevel(Level.FINEST); + break; + case "all": + PrePy.setLoggingLevel(Level.ALL); + break; + default: + throw new IllegalArgumentException("Invalid verbose option: '" + prop + "'"); } + } - Options.caseok = getBooleanOption("options.caseok", Options.caseok); - - Options.Qnew = getBooleanOption("options.Qnew", Options.Qnew); - - prop = PySystemState.registry.getProperty("python.division_warning"); - if (prop != null) { - if (prop.equalsIgnoreCase("old")) { - Options.division_warning = 0; - } else if (prop.equalsIgnoreCase("warn")) { - Options.division_warning = 1; - } else if (prop.equalsIgnoreCase("warnall")) { - Options.division_warning = 2; - } else { - throw Py.ValueError("Illegal division_warning option " - + "setting: '" + prop + "'"); - } + /** Set {@link division_warning} from {@link RegistryKey#PYTHON_DIVISION_WARNING}. */ + private static void setDivisionWarningFromRegistry() { + String prop; + switch ((prop = getStringOption(PYTHON_DIVISION_WARNING, "")).toLowerCase()) { + case "": + break; + case "old": + division_warning = 0; + break; + case "warn": + division_warning = 1; + break; + case "warnall": + division_warning = 2; + break; + default: + throw new IllegalArgumentException( + "Invalid division_warning option: '" + prop + "'"); } - - Options.sreCacheSpec = getStringOption("sre.cachespec", Options.sreCacheSpec); - - Options.importSite = getBooleanOption("import.site", Options.importSite); } + } diff --git a/src/org/python/core/ParserFacade.java b/src/org/python/core/ParserFacade.java index 49d5549f5..6eb64cdff 100644 --- a/src/org/python/core/ParserFacade.java +++ b/src/org/python/core/ParserFacade.java @@ -84,8 +84,8 @@ public static PyException fixParseError(ExpectedEncodingBufferedReader reader, int line=e.line; int col=e.charPositionInLine; if (node != null) { - line = node.getLine(); - col = node.getCharPositionInLine(); + line = node.getLineno(); + col = node.getCol_offset(); } String text= getLine(reader, line); String msg = e.getMessage(); diff --git a/src/org/python/core/PlainConsole.java b/src/org/python/core/PlainConsole.java index fa9b9d77c..9077f92b1 100644 --- a/src/org/python/core/PlainConsole.java +++ b/src/org/python/core/PlainConsole.java @@ -17,6 +17,8 @@ * System.in or System.out, or use a native library. It prompts on * System.out and reads from System.in (wrapped with the console * encoding). + * + * @see org.python.core.RegistryKey#PYTHON_CONSOLE */ public class PlainConsole implements Console { diff --git a/src/org/python/core/PrePy.java b/src/org/python/core/PrePy.java new file mode 100644 index 000000000..2f432c7b9 --- /dev/null +++ b/src/org/python/core/PrePy.java @@ -0,0 +1,490 @@ +package org.python.core; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessControlException; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jnr.posix.util.Platform; + +/** + * This class is part of the Jython run-time system, and contains only "pre-Python" data and methods + * that may safely be used before the type system is ready. The Jython type system springs into + * existence in response to a program's first use of any {@code PyObject}, for example when creating + * the first interpreter. When preparing an application (from the command line options, say) for + * creation of the first interpreter, it useful to defer type system creation until pre-Python + * configuration is complete. See PEP 432 for further rationale. + *

    + * Creation of the type system may happen as a side effect of referring using (almost) any object + * from a class that statically refers to a {@code PyObject}, for example {@code Py} or + * {@code PySystemState}. The present class is intended to hold utility methods and configuration + * useful in the pre-Python phase. + */ +// Do not refer to any PyObject, Py export or PySystemState in this class. +public class PrePy { + + // Logging functions are here so they may be used without starting the Jython runtime. + + /** Our name-spaced root logger is "org.python". */ + protected static final Logger logger = Logger.getLogger("org.python"); + protected static final Logger importLogger = Logger.getLogger("org.python.import"); + + /** {@link Options#verbose} level indicating an error that prevents correct results. */ + public static final int ERROR = -1; + /** {@link Options#verbose} level indicating an unexpected event, still working correctly. */ + public static final int WARNING = 0; + /** {@link Options#verbose} level for messages that confirm correct functioning. */ + public static final int MESSAGE = 1; + /** {@link Options#verbose} level providing detail during correct functioning. */ + public static final int COMMENT = 2; + /** {@link Options#verbose} level providing detail in support of debugging or tracing. */ + public static final int DEBUG = 3; + + static final Level[] LEVELS = {// + Level.OFF, // + Level.SEVERE, // Legacy: ERROR + Level.WARNING, // Legacy: WARNING + Level.INFO, // Legacy: MESSAGE + Level.CONFIG, // Legacy: COMMENT + Level.FINE, // Legacy: DEBUG + Level.FINER, Level.FINEST, Level.ALL}; + + /** + * Translate from the traditional "verbosity" system to JUL Level. We allow Jython verbosity + * values beyond the conventional range, treating values <{@link #ERROR} as {@code ERROR} + * (that is {@code Level.SEVERE}) and values >{@link #DEBUG} (that is {@code Level.FINE}) as + * {@code FINER}, {@code FINEST} and {@code ALL}. + * + * @param verbosity any integer verbosity, where the runtime default {@link #MESSAGE} = 1 + * @return a corresponding level where the default {@link #MESSAGE} produces {@code Level.INFO}. + */ + public static Level levelFromVerbosity(int verbosity) { + if (verbosity < ERROR) { + return Level.OFF; + } else if (verbosity >= LEVELS.length + (ERROR - 1)) { + return Level.ALL; + } else { + // Bound the index to the LEVELS array. + int index = verbosity - (ERROR - 1); + return LEVELS[index]; + } + } + + /** + * Translate from JUL Level to equivalent in the traditional "verbosity" system. We return + * Jython verbosity values beyond the conventional range, enough to enumerate the Java standard + * levels (e.g {@code FINER} returns 4 and {@code ALL} returns 6 ). + * + * @param level {@code java.util.logging.Level} to translate. + * @return integer verbosity, where the runtime default {@code INFO} = 1 + */ + public static int verbosityFromLevel(Level level) { + /* + * Find the least verbose setting v such that events at the given level or above will be + * logged by Jython, that is, v such that levelFromVerbosity(v) is a threshold no higher + * than the given level. We allow Jython verbosity values beyond the conventional range (e.g + * level==FINER), according to the range of values in the LEVELS array. + */ + int intLevel = level.intValue(); + int index = 0, v = ERROR - 1; // = OFF + while (index < LEVELS.length && LEVELS[index].intValue() > intLevel) { + assert LEVELS[index] == levelFromVerbosity(v); + index += 1; + v += 1; + } + return v; + } + + /** + * Convenience function to get the effective level of a given Logger, looking up the parent + * chain. If the root logger is reached without an explicit level set, assume + * {@code Level.INFO}. + */ + private static Level getEffectiveLoggingLevel(Logger logger) { + Level level = null; + while (logger != null && (level = logger.getLevel()) == null) { + logger = logger.getParent(); + } + return level != null ? level : Level.INFO; + } + + /** Convenience function to get the effective level of Logger "org.python". */ + public static Level getLoggingLevel() { + return getEffectiveLoggingLevel(logger); + } + + /** + * Used by {@link #maybeWrite(Level, String)}, the terminus of all verbosity-based logging + * calls, to detect changes made directly to {@link Options#verbose}. + */ + private static int savedVerbosity = MESSAGE; + + /** + * Set the level of the Jython logger "org.python" using the standard {@code java.util.logging} + * scale. For backward compatibility with the traditional "verbosity" system, make a + * corresponding setting of {@link Options#verbose}. + * + * @param newLevel to set + * @return previous logging level + */ + @SuppressWarnings("deprecation") + public static Level setLoggingLevel(Level newLevel) { + Level previousLevel = getLoggingLevel(); + if (newLevel != previousLevel) { + try { + logger.setLevel(newLevel); + } catch (SecurityException se) { + logger.warning("A security manager prevented a change to the logging level."); + newLevel = previousLevel; + } + } + savedVerbosity = Options.verbose = verbosityFromLevel(newLevel); + return previousLevel; + } + + /** + * Adjust the level of the Jython logger "org.python" using the traditional "verbosity" system: + * the bigger the number, the lower the logging threshold. This is primarily for the + * command-line Jython, where each "-v" increases the verbosity by one, on the + * {@code java.util.logging} scale. + * + * @param n increment on the scale {@code 1=INFO, 2=CONFIG, 3=FINE, ... } + */ + public static void increaseLoggingLevel(int n) { + int v = verbosityFromLevel(getLoggingLevel()); + setLoggingLevel(levelFromVerbosity(v + n)); + } + + /** + * Ensure that the logging system threshold is adjusted to match the legacy + * {@link Options#verbose} in the event that that has changed since we last looked. + */ + @SuppressWarnings("deprecation") + private static void syncLoggingLevel() { + if (Options.verbose != savedVerbosity) { + Level level = levelFromVerbosity(savedVerbosity = Options.verbose); + setLoggingLevel(level); + } + } + + /** Log a message at a specified level (if that level is not below the threshold). */ + @SuppressWarnings("deprecation") + public static void maybeWrite(String type, String msg, int verbosity) { + // If the caller is using the legacy logging system they may have changed Options.verbose. + syncLoggingLevel(); + if (verbosity <= Options.verbose) { + // Formulate the message in legacy style, then as a log message + logger.log(levelFromVerbosity(verbosity), "{0}: {1}", new Object[] {type, msg}); + } + } + + /** Submit a message to logging at the severity level ERROR. */ + public static void writeError(String type, String msg) { + maybeWrite(type, msg, ERROR); + } + + /** Submit a message to logging at the severity level WARNING. */ + public static void writeWarning(String type, String msg) { + maybeWrite(type, msg, WARNING); + } + + /** Submit a message to logging at the severity level MESSAGE. */ + public static void writeMessage(String type, String msg) { + maybeWrite(type, msg, MESSAGE); + } + + /** Submit a message to logging at the severity level COMMENT. */ + public static void writeComment(String type, String msg) { + maybeWrite(type, msg, COMMENT); + } + + /** Submit a message to logging at the severity level DEBUG. */ + public static void writeDebug(String type, String msg) { + maybeWrite(type, msg, DEBUG); + } + + /** + * Get the System properties if we are allowed to. Configuration values set via + * {@code -Dprop=value} to the java command will be found here. If a security manager prevents + * access, we will return a new (empty) object instead. + * + * @return {@code System} properties or a new {@code Properties} object + */ + public static Properties getSystemProperties() { + try { + return System.getProperties(); + } catch (AccessControlException ace) { + return new Properties(); + } + } + + /** + * Get a System property if it is defined, not null, and we are allowed to access it, otherwise + * return the given default. + * + * @param key of the entry to return + * @param defaultValue to return if null or disallowed + * @return property value or given default + */ + public static String getSystemProperty(String key, String defaultValue) { + try { + String value = System.getProperty(key, null); + return value != null ? value : defaultValue; + } catch (AccessControlException ace) { + return defaultValue; + } + } + + /** + * Determine whether standard input is an interactive stream. If the Java system property + * {@code python.launcher.tty} is defined and equal to {@code true} or {@code false}, then that + * provides the result. This property is normally supplied by the launcher. In the absence of + * this certainty, we use {@link #haveConsole()}. + * + * @return true if (we think) standard input is an interactive stream + */ + public static boolean isInteractive() { + // python.launcher.tty is authoritative; see http://bugs.jython.org/issue2325 + String tty = getSystemProperty("python.launcher.tty", ""); + if (tty.equalsIgnoreCase("true")) { + return true; + } else if (tty.equalsIgnoreCase("false")) { + return false; + } else { + // See if we have access to System.console() + return haveConsole(); + } + } + + /** Return {@code true} iff the console is accessible through System.console(). */ + public static boolean haveConsole() { + try { + return System.console() != null; + } catch (SecurityException se) { + return false; + } + } + + /** + * Check whether an input stream is interactive. This emulates CPython + * {@code Py_FdIsInteractive} within the constraints of pure Java. The input stream is + * considered ``interactive'' if either + *

      + *
    1. it is {@code System.in} and {@link #isInteractive()} is {@code true}, or
    2. + *
    3. the {@code -i} flag was given ({@link Options#interactive}={@code true}), and the + * filename associated with it is {@code null} or {@code ""} or {@code "???"}.
    4. + *
    + * + * @param fp stream (tested only for {@code System.in}) + * @param filename + * @return true iff thought to be interactive + */ + public static boolean isInteractive(InputStream fp, String filename) { + if (fp == System.in && isInteractive()) { + return true; + } else if (!Options.interactive) { + return false; + } else { + return filename == null || filename.equals("") || filename.equals("???"); + } + } + + /** + * Infers the usual Jython executable name from the position of the jar-file returned by + * {@link #getJarFileName()} by replacing the file name with "bin/jython". This is intended as + * an easy fallback for cases where {@code sys.executable} is {@code None} due to direct + * launching via the java executable. + *

    + * Note that this does not necessarily return the actual executable, but instead infers the + * place where it is usually expected to be. Use {@code sys.executable} to get the actual + * executable (may be {@code None}. + * + * @return usual Jython-executable as absolute path + */ + public static String getDefaultExecutableName() { + return getDefaultBinDir() + File.separator + + (Platform.IS_WINDOWS ? "jython.exe" : "jython"); + } + + /** + * Infers the usual Jython bin-dir from the position of the jar-file returned by + * {@link #getJarFileName()} byr replacing the file name with "bin". This is intended as an easy + * fallback for cases where {@code sys.executable} is {@code null} due to direct launching via + * the java executable. + *

    + * Note that this does not necessarily return the actual bin-directory, but instead infers the + * place where it is usually expected to be. + * + * @return usual Jython bin-dir as absolute path + */ + public static String getDefaultBinDir() { + String jar = _getJarFileName(); + return jar.substring(0, jar.lastIndexOf(File.separatorChar) + 1) + "bin"; + } + + /** + * Utility-method to obtain the name (including absolute path) of the currently used + * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or + * jython-standalone.jar or something custom. + * + * @return the full name of the jar file containing this class, null if not + * available. + */ + public static String getJarFileName() { + String jar = _getJarFileName(); + return jar; + } + + /** + * Utility-method to obtain the name (including absolute path) of the currently used + * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or + * jython-standalone.jar or something custom. + * + * @return the full name of the jar file containing this class, null if not + * available. + */ + private static String _getJarFileName() { + Class thisClass = PrePy.class; + String fullClassName = thisClass.getName(); + String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1); + URL url = thisClass.getResource(className + ".class"); + return getJarFileNameFromURL(url); + } + + /** + * Return the path in the file system (as a string) of a JAR located using the URL of a class + * file that it contains. Classes in Java can be asked for the URL of their associated resources + * (including their own class definition), and so the caller of this method may present such a + * URL as the basis for locating the JAR from which it came. + *

    + * Three protocols are supported, Java JAR-file protocol, and two JBoss protocols "vfs" and + * "vfszip". + *

    + * The JAR-file protocol URL, which must be a {@code jar:file:} reference to a contained element + * (that is, it has a "!/" part) is able to identify an actual JAR in a file system that may + * then be opened using {@code jarFile = new JarFile(jarFileName)}. The path to the JAR is + * returned. If the JAR is accessed by another mechanism ({@code http:} say) this will fail. + *

    + * The JBoss URL must be a reference to a class in {@code vfs:/org/python/core/}, or the + * same thing using the {@code vfszip:} protocol, where <JAR> stands for the absolute path + * to the Jython JAR in VFS. There is no "!/" marker: in JBoss VFS a JAR is treated just like a + * directory and can no longer be opened as a JAR. The method essentially just swaps a VFS + * protocol for the Java {@code file:} protocol. The path returned will be correct only if this + * naive swap is valid. + * + * @param url into the JAR + * @return the file path or {@code null} in the event of a detectable error + */ + public static String getJarFileNameFromURL(URL url) { + URI fileURI = null; + try { + switch (url == null ? "" : url.getProtocol()) { + + case "jar": + // url is jar:file:/some/path/some.jar!/package/with/A.class + if (Platform.IS_WINDOWS) { + // ... or jar:file://host/some/path/some.jar!/package/with/A.class + // ... or jar:file:////host/some/path/some.jar!/package/with/A.class + url = tweakWindowsFileURL(url); + } + URLConnection c = url.openConnection(); + fileURI = ((JarURLConnection) c).getJarFileURL().toURI(); + break; + + case "vfs": + case "vfszip": + // path is /some/path/some-jython.jar/org/python/core/some-name.class + String path = url.getPath(); + Pattern p = Pattern.compile("/([^./]+\\.jar)/org/python/core/\\w+.class"); + Matcher m = p.matcher(path); + if (m.find()) { + // path contains the target class in a JAR (named in group 1). + // Make a file URL from all the text up to the end of group 1. + fileURI = new URL("file:" + path.substring(0, m.end(1))).toURI(); + } + break; + + default: + // Unknown protocol or url==null: fileURI = null + break; + } + } catch (IOException | URISyntaxException | IllegalArgumentException e) { + // Handler cannot open connection or URL is malformed some way: fileURI = null + } + + // The JAR file is now identified in fileURI but needs decoding to a file + return fileURI == null ? null : new File(fileURI).toString(); + } + + /** + * If the argument is a {@code jar:file:} or {@code file:} URL, compensate for a bug in Java's + * construction of URLs affecting {@code java.io.File} and {@code java.net.URLConnection} on + * Windows. This is a helper for {@link #getJarFileNameFromURL(URL)}. + *

    + * This bug bites when a JAR file is at a (Windows) UNC location, and a {@code jar:file:} URL is + * derived from {@code Class.getResource()} as it is in {@link #_getJarFileName()}. When URL is + * supplied to {@link #getJarFileNameFromURL(URL)}, the bug leads to a URI that falsely treats a + * server as an "authority". It subsequently causes an {@code IllegalArgumentException} with the + * message "URI has an authority component" when we try to construct a File. See + * {@link https://bugs.java.com/view_bug.do?bug_id=6360233} ("won't fix"). + * + * @param url Possibly malformed URL + * @return corrected URL + */ + private static URL tweakWindowsFileURL(URL url) throws MalformedURLException { + String urlstr = url.toString(); + int fileIndex = urlstr.indexOf("file://"); // 7 chars + if (fileIndex >= 0) { + // Intended UNC path. If there is no slash following these two, insert "/" here: + int insert = fileIndex + 7; + if (urlstr.length() > insert && urlstr.charAt(insert) != '/') { + url = new URL(urlstr.substring(0, insert) + "//" + urlstr.substring(insert)); + } + } + return url; + } + + /** + * Run a command as a sub-process and return as the result the first line of output that + * consists of more than white space. It returns "" on any kind of error. + * + * @param command as strings (as for ProcessBuilder) + * @return the first line with content, or "" + */ + public static String getCommandResult(String... command) { + String result = "", line = null; + ProcessBuilder pb = new ProcessBuilder(command); + try { + Process p = pb.start(); + java.io.BufferedReader br = + new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream())); + // We read to the end-of-stream in case the sub-process cannot end cleanly without. + while ((line = br.readLine()) != null) { + if (line.length() > 0 && result.length() == 0) { + // This is the first line with content (maybe). + result = line.trim(); + } + } + br.close(); + // Now we wait for the sub-process to terminate nicely. + if (p.waitFor() != 0) { + // Bad exit status: don't take the result. + result = ""; + } + } catch (IOException | InterruptedException | SecurityException e) { + result = ""; + } + return result; + } +} diff --git a/src/org/python/core/Py.java b/src/org/python/core/Py.java index ac7016ac4..29247f1a7 100644 --- a/src/org/python/core/Py.java +++ b/src/org/python/core/Py.java @@ -2,68 +2,40 @@ package org.python.core; import java.io.ByteArrayOutputStream; +import java.io.CharArrayWriter; import java.io.File; -import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.ObjectStreamException; import java.io.OutputStream; -import java.io.PrintStream; +import java.io.PrintWriter; import java.io.Serializable; import java.io.StreamCorruptedException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.URL; -import java.net.URLDecoder; import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; import java.util.List; -import java.util.Set; - -import com.google.common.base.CharMatcher; -import jline.console.UserInterruptException; -import jnr.constants.Constant; -import jnr.constants.platform.Errno; -import jnr.posix.POSIX; -import jnr.posix.POSIXFactory; -import jnr.posix.util.Platform; +import java.util.logging.Level; import org.python.antlr.base.mod; import org.python.core.adapter.ClassicPyObjectAdapter; import org.python.core.adapter.ExtensiblePyObjectAdapter; -import org.python.core.Traverseproc; -import org.python.core.Visitproc; import org.python.modules.posix.PosixModule; -import org.python.util.Generic; - -/** Builtin types that are used to setup PyObject. - * - * Resolve circular dependency with some laziness. */ -class BootstrapTypesSingleton { - private final Set> BOOTSTRAP_TYPES; - private BootstrapTypesSingleton() { - BOOTSTRAP_TYPES = Generic.set(); - BOOTSTRAP_TYPES.add(PyObject.class); - BOOTSTRAP_TYPES.add(PyType.class); - BOOTSTRAP_TYPES.add(PyBuiltinCallable.class); - BOOTSTRAP_TYPES.add(PyDataDescr.class); - } - private static class LazyHolder { - private static final BootstrapTypesSingleton INSTANCE = new BootstrapTypesSingleton(); - } +import com.google.common.base.CharMatcher; - public static Set> getInstance() { - return LazyHolder.INSTANCE.BOOTSTRAP_TYPES; - } -} +import jline.console.UserInterruptException; +import jnr.constants.Constant; +import jnr.constants.platform.Errno; +import jnr.posix.util.Platform; -public final class Py { +public final class Py extends PrePy { static class SingletonResolver implements Serializable { @@ -84,9 +56,10 @@ private Object readResolve() throws ObjectStreamException { throw new StreamCorruptedException("unknown singleton: " + which); } } + /* Holds the singleton None and Ellipsis objects */ /** The singleton None Python object **/ - public final static PyObject None = new PyNone(); + public final static PyObject None = PyNone.getInstance(); /** The singleton Ellipsis Python object - written as ... when indexing */ public final static PyObject Ellipsis = new PyEllipsis(); /** The singleton NotImplemented Python object. Used in rich comparison */ @@ -94,8 +67,7 @@ private Object readResolve() throws ObjectStreamException { /** A zero-length array of Strings to pass to functions that don't have any keyword arguments **/ public final static String[] NoKeywords = new String[0]; - /** A zero-length array of PyObject's to pass to functions that - expect zero-arguments **/ + /** A zero-length array of PyObject's to pass to functions when we have no arguments **/ public final static PyObject[] EmptyObjects = new PyObject[0]; /** A frozenset with zero elements **/ public final static PyFrozenSet EmptyFrozenSet = new PyFrozenSet(); @@ -129,7 +101,6 @@ private Object readResolve() throws ObjectStreamException { public final static long TPFLAGS_IS_ABSTRACT = 1L << 20; - /** A unique object to indicate no conversion is possible in __tojava__ methods **/ public final static Object NoConversion = new PySingleton("Error"); @@ -222,6 +193,10 @@ public static PyException IOError(Constant errno) { return new PyException(Py.IOError, args); } + public static PyException IOError(Constant errno, String filename) { + return IOError(errno, Py.fileSystemEncode(filename)); + } + public static PyException IOError(Constant errno, PyObject filename) { int value = errno.intValue(); PyObject args = new PyTuple(Py.newInteger(value), PosixModule.strerror(value), filename); @@ -235,7 +210,7 @@ private static PyException fromIOException(IOException ioe, PyObject err) { } if (ioe instanceof FileNotFoundException) { PyTuple args = new PyTuple(Py.newInteger(Errno.ENOENT.intValue()), - Py.newString("File not found - " + message)); + Py.newStringOrUnicode("File not found - " + message)); return new PyException(err, args); } return new PyException(err, message); @@ -294,26 +269,50 @@ public static PyException UnboundLocalError(String message) { static void maybeSystemExit(PyException exc) { if (exc.match(Py.SystemExit)) { + // No actual exit here if Options.interactive (-i flag) is in force. + handleSystemExit(exc); + } + } + + /** + * Exit the process, if {@value Options#inspect}{@code ==false}, cleaning up the system state. + * This exception (normally SystemExit) determines the message, if any, and the + * {@code System.exit} status. + * + * @param exc supplies the message or exit status + */ + static void handleSystemExit(PyException exc) { + if (!Options.inspect) { PyObject value = exc.value; if (PyException.isExceptionInstance(exc.value)) { value = value.__findattr__("code"); } - Py.getSystemState().callExitFunc(); + + // Decide exit status and produce message while Jython still works + int exitStatus; if (value instanceof PyInteger) { - System.exit(((PyInteger) value).getValue()); + exitStatus = ((PyInteger) value).getValue(); } else { if (value != Py.None) { try { Py.println(value); - System.exit(1); + exitStatus = 1; } catch (Throwable t) { - // continue + exitStatus = 0; } + } else { + exitStatus = 0; } - System.exit(0); } + + // Shut down Jython + PySystemState sys = Py.getSystemState(); + sys.callExitFunc(); + sys.close(); + System.exit(exitStatus); } } + public static PyObject StopIteration; public static PyException StopIteration(String message) { @@ -562,6 +561,7 @@ private Py() { @param o the PyObject to convert. @param c the class to convert it to. **/ + @SuppressWarnings("unchecked") public static T tojava(PyObject o, Class c) { Object obj = o.__tojava__(c); if (obj == Py.NoConversion) { @@ -667,7 +667,7 @@ public static PyString newStringOrUnicode(String s) { * s. */ public static PyString newStringOrUnicode(PyObject precedent, String s) { - if (!(precedent instanceof PyUnicode) && CharMatcher.ASCII.matchesAllOf(s)) { + if (!(precedent instanceof PyUnicode) && CharMatcher.ascii().matchesAllOf(s)) { return Py.newString(s); } else { return Py.newUnicode(s); @@ -675,7 +675,7 @@ public static PyString newStringOrUnicode(PyObject precedent, String s) { } public static PyString newStringUTF8(String s) { - if (CharMatcher.ASCII.matchesAllOf(s)) { + if (CharMatcher.ascii().matchesAllOf(s)) { // ascii of course is a subset of UTF-8 return Py.newString(s); } else { @@ -683,11 +683,170 @@ public static PyString newStringUTF8(String s) { } } - public static PyStringMap newStringMap() { - // enable lazy bootstrapping (see issue #1671) - if (!PyType.hasBuilder(PyStringMap.class)) { - BootstrapTypesSingleton.getInstance().add(PyStringMap.class); + /** + * Return a file name or path as Unicode (Java UTF-16 String), decoded if necessary + * from a Python bytes object, using the file system encoding. In Jython, this + * encoding is UTF-8, irrespective of the OS platform. This method is comparable with Python 3 + * os.fsdecode, but for Java use, in places such as the os module. If + * the argument is not a PyUnicode, it will be decoded using the nominal Jython + * file system encoding. If the argument is a PyUnicode, its + * String is returned. + * + * @param filename as bytes to decode, or already as unicode + * @return unicode version of path + */ + public static String fileSystemDecode(PyString filename) { + String s = filename.getString(); + if (filename instanceof PyUnicode || CharMatcher.ascii().matchesAllOf(s)) { + // Already encoded or usable as ASCII + return s; + } else { + // It's bytes, so must decode properly + assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString()); + return codecs.PyUnicode_DecodeUTF8(s, null); + } + } + + /** + * As {@link #fileSystemDecode(PyString)} but raising ValueError if not a + * str or unicode. + * + * @param filename as bytes to decode, or already as unicode + * @return unicode version of the file name + */ + public static String fileSystemDecode(PyObject filename) { + if (filename instanceof PyString) { + return fileSystemDecode((PyString)filename); + } else { + throw Py.TypeError(String.format("coercing to Unicode: need string, %s type found", + filename.getType().fastGetName())); + } + } + + /** + * Return a PyString object we can use as a file name or file path in places where Python + * expects a bytes (that is a str) object in the file system encoding. + * In Jython, this encoding is UTF-8, irrespective of the OS platform. + *

    + * This is subtly different from CPython's use of "file system encoding", which tracks the + * platform's choice so that OS services may be called that have a bytes interface. Jython's + * interaction with the OS occurs via Java using String arguments representing Unicode values, + * so we have no need to match the encoding actually chosen by the platform (e.g. 'mbcs' on + * Windows). Rather we need a nominal Jython file system encoding, for use where the standard + * library forces byte paths on us (in Python 2). There is no reason for this choice to vary + * with OS platform. Methods receiving paths as bytes will + * {@link #fileSystemDecode(PyString)} them again for Java. + * + * @param filename as unicode to encode, or already as bytes + * @return encoded bytes version of path + */ + public static PyString fileSystemEncode(String filename) { + if (CharMatcher.ascii().matchesAllOf(filename)) { + // Just wrap it as US-ASCII is a subset of the file system encoding + return Py.newString(filename); + } else { + // It's non just US-ASCII, so must encode properly + assert "utf-8".equals(PySystemState.FILE_SYSTEM_ENCODING.toString()); + return Py.newString(codecs.PyUnicode_EncodeUTF8(filename, null)); + } + } + + /** + * Return a PyString object we can use as a file name or file path in places where Python + * expects a bytes (that is, str) object in the file system encoding. + * In Jython, this encoding is UTF-8, irrespective of the OS platform. This method is comparable + * with Python 3 os.fsencode. If the argument is a PyString, it is returned + * unchanged. If the argument is a PyUnicode, it is converted to a bytes using the + * nominal Jython file system encoding. + * + * @param filename as unicode to encode, or already as bytes + * @return encoded bytes version of path + */ + public static PyString fileSystemEncode(PyString filename) { + return (filename instanceof PyUnicode) ? fileSystemEncode(filename.getString()) : filename; + } + + /** + * Convert a PyList path to a list of Java String objects decoded from + * the path elements to strings guaranteed usable in the Java API. + * + * @param path a Python search path + * @return equivalent Java list + */ + private static List fileSystemDecode(PyList path) { + List list = new ArrayList<>(path.__len__()); + for (PyObject filename : path.getList()) { + list.add(fileSystemDecode(filename)); } + return list; + } + + /** + * Get the environment variables from {@code os.environ}. Keys and values should be + * {@code PyString}s in the file system encoding, and it may be a {@code dict} but nothing can + * be guaranteed. (Note that in the case of multiple interpreters, the target is in the current + * interpreter's copy of {@code os}.) + * + * @return {@code os.environ} + */ + private static PyObject getEnvironment() { + PyObject os = imp.importName("os", true); + PyObject environ = os.__getattr__("environ"); + return environ; + } + + /** The same as {@code getenv(name, null)}. See {@link #getenv(PyString, PyString)}. */ + public static PyString getenv(PyString name) { + return getenv(name, null); + } + + /** + * Get the value of the environment variable named from {@code os.environ} or return the given + * default value. Empty string values are treated as undefined for this purpose. + * + * @param name of the environment variable. + * @param defaultValue to return if {@code key} is not defined (may be {@code null}. + * @return the corresponding value or defaultValue. + */ + public static PyString getenv(PyString name, PyString defaultValue) { + try { + PyObject value = getEnvironment().__finditem__(name); + if (value == null) { + return defaultValue; + } else { + return value.__str__(); + } + } catch (PyException e) { + // Something is fishy about os.environ, so the name is not defined. + return defaultValue; + } + } + + /** The same as {@code getenv(name, null)}. See {@link #getenv(String, String)}. */ + public static String getenv(String name) { + return getenv(name, null); + } + + /** + * Get the value of the environment variable named from {@code os.environ} or return the given + * default value. This is a convenience wrapper on {@link #getenv(PyString, PyString)} which + * takes care of the fact that environment variables are FS-encoded. + * + * @param name to access in the environment. + * @param defaultValue to return if {@code key} is not defined. + * @return the corresponding value or defaultValue. + */ + public static String getenv(String name, String defaultValue) { + PyString value = getenv(newUnicode(name), null); + if (value == null) { + return defaultValue; + } else { + // Environment variables are FS-encoded byte strings + return fileSystemDecode(value); + } + } + + public static PyStringMap newStringMap() { return new PyStringMap(); } @@ -901,99 +1060,94 @@ public static synchronized boolean initPython() { private static boolean syspathJavaLoaderRestricted = false; /** - * Common code for findClass and findClassEx - * @param name Name of the Java class to load and initialize - * @param reason Reason for loading it, used for debugging. No debug output - * is generated if it is null + * Common code for {@link #findClass(String)} and {@link #findClassEx(String, String)}. + * + * @param name of the Java class to load and initialise + * @param reason to be given in debug output (or {@code null} to suppress debug output. * @return the loaded class * @throws ClassNotFoundException if the class wasn't found by the class loader */ - private static Class findClassInternal(String name, String reason) throws ClassNotFoundException { + private static Class findClassInternal(String name, String reason) + throws ClassNotFoundException { + ClassLoader classLoader = Py.getSystemState().getClassLoader(); if (classLoader != null) { - if (reason != null) { - writeDebug("import", "trying " + name + " as " + reason + - " in sys.classLoader"); - } + findClassTrying(name, reason, classLoader, "sys.classLoader"); return loadAndInitClass(name, classLoader); } + if (!syspathJavaLoaderRestricted) { try { classLoader = imp.getSyspathJavaLoader(); - if (classLoader != null && reason != null) { - writeDebug("import", "trying " + name + " as " + reason + - " in SysPathJavaLoader"); - } + findClassTrying(name, reason, classLoader, "SysPathJavaLoader"); } catch (SecurityException e) { syspathJavaLoaderRestricted = true; } } + if (syspathJavaLoaderRestricted) { classLoader = imp.getParentClassLoader(); - if (classLoader != null && reason != null) { - writeDebug("import", "trying " + name + " as " + reason + - " in Jython's parent class loader"); - } + findClassTrying(name, reason, classLoader, "Jython's parent class loader"); } + if (classLoader != null) { try { return loadAndInitClass(name, classLoader); } catch (ClassNotFoundException cnfe) { // let the default classloader try - // XXX: by trying another classloader that may not be on a - // parent/child relationship with the Jython's parent - // classsloader we are risking some nasty class loading - // problems (such as having two incompatible copies for - // the same class that is itself a dependency of two - // classes loaded from these two different class loaders) + /* + * XXX: by trying another classloader that may not be on a parent/child relationship + * with the Jython's parent classsloader we are risking some nasty class loading + * problems (such as having two incompatible copies for the same class that is + * itself a dependency of two classes loaded from these two different class + * loaders). + */ } } - if (reason != null) { - writeDebug("import", "trying " + name + " as " + reason + - " in context class loader, for backwards compatibility"); + + classLoader = Thread.currentThread().getContextClassLoader(); + findClassTrying(name, reason, classLoader, + "context class loader, for backwards compatibility"); + return loadAndInitClass(name, classLoader); + } + + private static void findClassTrying(String name, String reason, ClassLoader cl, String place) { + if (cl != null && reason != null && importLogger.isLoggable(Level.FINE)) { + importLogger.log(Level.FINE, "# trying {0} as {1} in {2}", + new Object[] {name, reason, place}); } - return loadAndInitClass(name, Thread.currentThread().getContextClassLoader()); } /** - * Tries to find a Java class. - * @param name Name of the Java class. - * @return The class, or null if it wasn't found + * Find and load a Java class by name. + * + * @param name of the Java class. + * @return the class, or {@code null} if it wasn't found or something went wrong */ public static Class findClass(String name) { try { return findClassInternal(name, null); - } catch (ClassNotFoundException e) { - // e.printStackTrace(); - return null; - } catch (IllegalArgumentException e) { - // e.printStackTrace(); - return null; - } catch (NoClassDefFoundError e) { - // e.printStackTrace(); + } catch (ClassNotFoundException | IllegalArgumentException | NoClassDefFoundError e) { + // e.printStackTrace(); return null; } } /** - * Tries to find a Java class. + * Find and load a Java class by name. * - * Unless {@link #findClass(String)}, it raises a JavaError - * if the class was found but there were problems loading it. * @param name Name of the Java class. - * @param reason Reason for finding the class. Used for debugging messages. - * @return The class, or null if it wasn't found - * @throws JavaError wrapping LinkageErrors/IllegalArgumentExceptions - * occurred when the class is found but can't be loaded. + * @param reason for finding the class. Used in debugging messages. + * @return the class, or {@code null} if it simply wasn't found + * @throws PyException {@code JavaError} wrapping errors occurring when the class is found but + * cannot be loaded. */ - public static Class findClassEx(String name, String reason) { + public static Class findClassEx(String name, String reason) throws PyException { try { return findClassInternal(name, reason); } catch (ClassNotFoundException e) { return null; - } catch (IllegalArgumentException e) { - throw JavaError(e); - } catch (LinkageError e) { + } catch (IllegalArgumentException | LinkageError e) { throw JavaError(e); } } @@ -1001,11 +1155,11 @@ public static Class findClassEx(String name, String reason) { // An alias to express intent (since boolean flags aren't exactly obvious). // We *need* to initialize classes on findClass/findClassEx, so that import // statements can trigger static initializers - private static Class loadAndInitClass(String name, ClassLoader loader) throws ClassNotFoundException { + private static Class loadAndInitClass(String name, ClassLoader loader) + throws ClassNotFoundException { return Class.forName(name, true, loader); } - public static void initProxy(PyProxy proxy, String module, String pyclass, Object[] args) { if (proxy._getPyInstance() != null) { @@ -1073,11 +1227,11 @@ public static void runMain(CodeBootstrap main, String[] args) } Py.getSystemState().callExitFunc(); } - //XXX: this needs review to make sure we are cutting out all of the Java - // exceptions. + + //XXX: this needs review to make sure we are cutting out all of the Java exceptions. private static String getStackTrace(Throwable javaError) { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - javaError.printStackTrace(new PrintStream(buf)); + CharArrayWriter buf = new CharArrayWriter(); + javaError.printStackTrace(new PrintWriter(buf)); String str = buf.toString(); int index = -1; @@ -1109,15 +1263,35 @@ private static String getStackTrace(Throwable javaError) { return str; } - /* Display a PyException and stack trace */ + /** + * Display an exception and stack trace through + * {@link #printException(Throwable, PyFrame, PyObject)}. + * + * @param t to display + */ public static void printException(Throwable t) { printException(t, null, null); } + /** + * Display an exception and stack trace through + * {@link #printException(Throwable, PyFrame, PyObject)}. + * + * @param t to display + * @param f frame at which to start the stack trace + */ public static void printException(Throwable t, PyFrame f) { printException(t, f, null); } + /** + * Display an exception and stack trace. If the exception was {@link Py#SystemExit} and + * {@link Options#inspect}{@code ==false}, this will exit the JVM. + * + * @param t to display + * @param f frame at which to start the stack trace + * @param file output onto this stream or {@link Py#stderr} if {@code null} + */ public static synchronized void printException(Throwable t, PyFrame f, PyObject file) { StdoutWrapper stderr = Py.stderr; @@ -1139,6 +1313,7 @@ public static synchronized void printException(Throwable t, PyFrame f, PyException exc = Py.JavaError(t); + // Act on SystemExit here. maybeSystemExit(exc); setException(exc, f); @@ -1170,31 +1345,107 @@ public static synchronized void printException(Throwable t, PyFrame f, ts.exception = null; } - public static void displayException(PyObject type, PyObject value, PyObject tb, - PyObject file) { + /** + * Print the description of an exception as a big string. The arguments are closely equivalent + * to the tuple returned by Python sys.exc_info, on standard error or a given + * byte-oriented file. Compare with Python traceback.print_exception. + * + * @param type of exception + * @param value the exception parameter (second argument to raise) + * @param tb traceback of the call stack where the exception originally occurred + * @param file to print encoded string to, or null meaning standard error + */ + public static void displayException(PyObject type, PyObject value, PyObject tb, PyObject file) { + + // Output is to standard error, unless a file object has been given. StdoutWrapper stderr = Py.stderr; + + // As we format the exception in Unicode, we deal with encoding in this method + String encoding, errors = codecs.REPLACE; + if (file != null) { + // Ostensibly writing to a file: assume file content encoding (file.encoding) stderr = new FixedFileWrapper(file); + encoding = codecs.getDefaultEncoding(); + } else { + // Not a file, assume we should encode for the console + encoding = getAttr(Py.getSystemState().__stderr__, "encoding", null); } + + // But if the stream can tell us directly, of course we use that answer. + encoding = getAttr(stderr.myFile(), "encoding", encoding); + errors = getAttr(stderr.myFile(), "errors", errors); + flushLine(); + // The creation of the report operates entirely in Java String (to support Unicode). + try { + // Be prepared for formatting or printing to fail + PyString bytes = exceptionToBytes(type, value, tb, encoding, errors); + stderr.print(bytes); + } catch (Exception ex) { + // Looks like that exception just won't convert or print + value = Py.newString(""); + PyString bytes = exceptionToBytes(type, value, tb, encoding, errors); + stderr.print(bytes); + } + } + + /** Get a String attribute from an object or a return a default. */ + private static String getAttr(PyObject target, String internedName, String def) { + PyObject attr = target.__findattr__(internedName); + if (attr == null) { + return def; + } else if (attr instanceof PyUnicode) { + return ((PyUnicode)attr).getString(); + } else { + return attr.__str__().getString(); + } + } + + /** + * Helper for {@link #displayException(PyObject, PyObject, PyObject, PyObject)}, falling back to + * US-ASCII as the last resort encoding. + */ + private static PyString exceptionToBytes(PyObject type, PyObject value, PyObject tb, + String encoding, String errors) { + String string = exceptionToString(type, value, tb); + String bytes; // not UTF-16 + try { + // Format the exception and stack-trace in all its glory + bytes = codecs.encode(Py.newUnicode(string), encoding, errors); + } catch (Exception ex) { + // Sometimes a working codec is just too much to ask + bytes = codecs.PyUnicode_EncodeASCII(string, string.length(), codecs.REPLACE); + } + return Py.newString(bytes); + } + + /** + * Format the description of an exception as a big string. The arguments are closely equivalent + * to the tuple returned by Python sys.exc_info. Compare with Python + * traceback.format_exception. + * + * @param type of exception + * @param value the exception parameter (second argument to raise) + * @param tb traceback of the call stack where the exception originally occurred + * @return string representation of the traceback and exception + */ + static String exceptionToString(PyObject type, PyObject value, PyObject tb) { + + // Compose the stack dump, syntax error, and actual exception in this buffer: + StringBuilder buf; + if (tb instanceof PyTraceback) { - stderr.print(((PyTraceback) tb).dumpStack()); + buf = new StringBuilder(((PyTraceback)tb).dumpStack()); + } else { + buf = new StringBuilder(); } + if (__builtin__.isinstance(value, Py.SyntaxError)) { - PyObject filename = value.__findattr__("filename"); - PyObject text = value.__findattr__("text"); - PyObject lineno = value.__findattr__("lineno"); - stderr.print(" File \""); - stderr.print(filename == Py.None || filename == null ? - "" : filename.toString()); - stderr.print("\", line "); - stderr.print(lineno == null ? Py.newString("0") : lineno); - stderr.print("\n"); - if (text != Py.None && text != null && text.__len__() != 0) { - printSyntaxErrorText(stderr, value.__findattr__("offset").asInt(), - text.toString()); - } + // The value part of the exception is a syntax error: first emit that. + appendSyntaxError(buf, value); + // Now supersede it with just the syntax error message for the next phase. value = value.__findattr__("msg"); if (value == null) { value = Py.None; @@ -1203,26 +1454,46 @@ public static void displayException(PyObject type, PyObject value, PyObject tb, if (value.getJavaProxy() != null) { Object javaError = value.__tojava__(Throwable.class); - if (javaError != null && javaError != Py.NoConversion) { - stderr.println(getStackTrace((Throwable) javaError)); + // The value is some Java Throwable: append that too + buf.append(getStackTrace((Throwable)javaError)); } } - try { - stderr.println(formatException(type, value)); - } catch (Exception ex) { - stderr.println(formatException(type, Py.None)); + + // Formatting the value may raise UnicodeEncodeError: client must deal + buf.append(formatException(type, value)).append('\n'); + return buf.toString(); + } + + /** + * Helper to {@link #tracebackToString(PyObject, PyObject)} when the value in an exception turns + * out to be a syntax error. + */ + private static void appendSyntaxError(StringBuilder buf, PyObject value) { + + PyObject filename = value.__findattr__("filename"); + PyObject text = value.__findattr__("text"); + PyObject lineno = value.__findattr__("lineno"); + + buf.append(" File \""); + buf.append(filename == Py.None || filename == null ? "" : filename.toString()); + buf.append("\", line "); + buf.append(lineno == null ? Py.newString('0') : lineno); + buf.append('\n'); + + if (text != Py.None && text != null && text.__len__() != 0) { + appendSyntaxErrorText(buf, value.__findattr__("offset").asInt(), text.toString()); } } /** - * Print the two lines showing where a SyntaxError was caused. + * Generate two lines showing where a SyntaxError was caused. * - * @param out StdoutWrapper to print to + * @param buf to append with generated message text * @param offset the offset into text - * @param text a source code String line + * @param text a source code line */ - private static void printSyntaxErrorText(StdoutWrapper out, int offset, String text) { + private static void appendSyntaxErrorText(StringBuilder buf, int offset, String text) { if (offset >= 0) { if (offset > 0 && offset == text.length()) { offset--; @@ -1250,19 +1521,21 @@ private static void printSyntaxErrorText(StdoutWrapper out, int offset, String t text = text.substring(i, text.length()); } - out.print(" "); - out.print(text); + buf.append(" "); + buf.append(text); if (text.length() == 0 || !text.endsWith("\n")) { - out.print("\n"); + buf.append('\n'); } if (offset == -1) { return; } - out.print(" "); + + // The indicator line " ^" + buf.append(" "); for (offset--; offset > 0; offset--) { - out.print(" "); + buf.append(' '); } - out.print("^\n"); + buf.append("^\n"); } public static String formatException(PyObject type, PyObject value) { @@ -1290,26 +1563,39 @@ public static String formatException(PyObject type, PyObject value, boolean useR } buf.append(className); } else { - buf.append(useRepr ? type.__repr__() : type.__str__()); + // Never happens since Python 2.7? Do something sensible anyway. + buf.append(asMessageString(type, useRepr)); } + if (value != null && value != Py.None) { - // only print colon if the str() of the object is not the empty string - PyObject s = useRepr ? value.__repr__() : value.__str__(); - if (!(s instanceof PyString) || s.__len__() != 0) { - buf.append(": "); + String s = asMessageString(value, useRepr); + // Print colon and object (unless it renders as "") + if (s.length() > 0) { + buf.append(": ").append(s); } - buf.append(s); } + return buf.toString(); } + /** Defensive method to avoid exceptions from decoding (or import encodings) */ + private static String asMessageString(PyObject value, boolean useRepr) { + if (useRepr) { + value = value.__repr__(); + } + if (value instanceof PyUnicode) { + return value.asString(); + } else { + return value.__str__().getString(); + } + } + public static void writeUnraisable(Throwable unraisable, PyObject obj) { PyException pye = JavaError(unraisable); stderr.println(String.format("Exception %s in %s ignored", formatException(pye.type, pye.value, true), obj)); } - /* Equivalent to Python's assert statement */ public static void assert_(PyObject test, PyObject message) { if (!test.__nonzero__()) { @@ -1537,35 +1823,19 @@ public static void installConsole(Console console) throws UnsupportedOperationEx } } - /** - * Check (using the {@link POSIX} library and jnr-posix library) whether we are in - * an interactive environment. Amongst other things, this affects the type of console that may - * be legitimately installed during system initialisation. Note that the result may vary - * according to whether a jnr-posix native library is found along - * java.library.path, or the pure Java fall-back is used. - * - * @return true if (we think) we are in an interactive environment - */ - public static boolean isInteractive() { - // python.launcher.tty is authoratative; see http://bugs.jython.org/issue2325 - String isTTY = System.getProperty("python.launcher.tty"); - if (isTTY != null && isTTY.equals("true")) { - return true; - } - if (isTTY != null && isTTY.equals("false")) { - return false; - } - // Decide if System.in is interactive - try { - POSIX posix = POSIXFactory.getPOSIX(); - FileDescriptor in = FileDescriptor.in; - return posix.isatty(in); - } catch (SecurityException ex) { - return false; - } - } + private static final String IMPORT_SITE_ERROR = "" + + "Cannot import site module and its dependencies: %s\n" + + "Determine if the following attributes are correct:\n" // + + " * sys.path: %s\n" + + " This attribute might be including the wrong directories, such as from CPython\n" + + " * sys.prefix: %s\n" + + " This attribute is set by the system property python.home, although it can\n" + + " be often automatically determined by the location of the Jython jar file\n\n" + + "You can use the -S option or python.import.site=false to not import the site module"; public static boolean importSiteIfSelected() { + // Ensure sys.flags.no_site actually reflects what happened. (See docs of these two.) + Options.no_site = !Options.importSite; if (Options.importSite) { try { // Ensure site-packages are available @@ -1574,18 +1844,10 @@ public static boolean importSiteIfSelected() { } catch (PyException pye) { if (pye.match(Py.ImportError)) { PySystemState sys = Py.getSystemState(); - throw Py.ImportError(String.format("" - + "Cannot import site module and its dependencies: %s\n" - + "Determine if the following attributes are correct:\n" - + " * sys.path: %s\n" - + " This attribute might be including the wrong directories, such as from CPython\n" - + " * sys.prefix: %s\n" - + " This attribute is set by the system property python.home, although it can\n" - + " be often automatically determined by the location of the Jython jar file\n\n" - + "You can use the -S option or python.import.site=false to not import the site module", - pye.value.__getattr__("args").__getitem__(0), - sys.path, - sys.prefix)); + String value = pye.value.__getattr__("args").__getitem__(0).toString(); + List path = fileSystemDecode(sys.path); + String prefix = fileSystemDecode(PySystemState.prefix); + throw Py.ImportError(String.format(IMPORT_SITE_ERROR, value, path, prefix)); } else { throw pye; } @@ -2052,37 +2314,6 @@ public static long java_obj_id(Object o) { public static void printResult(PyObject ret) { Py.getThreadState().getSystemState().invoke("displayhook", ret); } - public static final int ERROR = -1; - public static final int WARNING = 0; - public static final int MESSAGE = 1; - public static final int COMMENT = 2; - public static final int DEBUG = 3; - - public static void maybeWrite(String type, String msg, int level) { - if (level <= Options.verbose) { - System.err.println(type + ": " + msg); - } - } - - public static void writeError(String type, String msg) { - maybeWrite(type, msg, ERROR); - } - - public static void writeWarning(String type, String msg) { - maybeWrite(type, msg, WARNING); - } - - public static void writeMessage(String type, String msg) { - maybeWrite(type, msg, MESSAGE); - } - - public static void writeComment(String type, String msg) { - maybeWrite(type, msg, COMMENT); - } - - public static void writeDebug(String type, String msg) { - maybeWrite(type, msg, DEBUG); - } public static void saveClassFile(String name, ByteArrayOutputStream bytestream) { String dirname = Options.proxyDebugDirectory; @@ -2259,18 +2490,25 @@ private static boolean abstractIsSubClass(PyObject derived, PyObject cls) { * checker */ private static PyObject dispatchToChecker(PyObject checkerArg, PyObject cls, - String checkerName) { + String checkerName) { //Ignore old style classes. if (cls instanceof PyClass) { return null; } - - PyObject checker = cls.__findattr__(checkerName); - if (checker == null) { + /* Here we would actually like to call cls.__findattr__("__metaclass__") + * rather than cls.getType(). However there are circumstances where the + * metaclass doesn't show up as __metaclass__. On the other hand we need + * to avoid that checker refers to builtin type___subclasscheck__ or + * type___instancecheck__. Filtering out checker-instances of + * PyBuiltinMethodNarrow does the trick. We also filter out PyMethodDescr + * to shortcut some unnecessary looping. + */ + PyObject checker = cls.getType().__findattr__(checkerName); + if (checker == null || checker instanceof PyMethodDescr || + checker instanceof PyBuiltinMethodNarrow) { return null; } - - return checker.__call__(checkerArg); + return checker.__call__(cls, checkerArg); } /** @@ -2291,175 +2529,32 @@ private static void checkClass(PyObject cls, String message) { } } + /** + * Turn any Python iterable into an array of its elements. + * + * @param iterable to evaluate + * @return array of elements from iterable + */ static PyObject[] make_array(PyObject iterable) { // Special-case the common tuple and list cases, for efficiency if (iterable instanceof PySequenceList) { return ((PySequenceList) iterable).getArray(); - } - - // Guess result size and allocate space. The typical make_array arg supports - // __len__, with one exception being generators, so avoid the overhead of an - // exception from __len__ in their case - int n = 10; - if (!(iterable instanceof PyGenerator)) { - try { - n = iterable.__len__(); - } catch (PyException pye) { - // ok + } else { + int n = 10; + if (!(iterable instanceof PyGenerator)) { + try { + n = iterable.__len__(); // may be available, otherwise ... + } catch (PyException pye) { /* ... leave n at 0 */ } } + List objs = new ArrayList(n); + for (PyObject item : iterable.asIterable()) { + objs.add(item); + } + return objs.toArray(Py.EmptyObjects); } - - List objs = new ArrayList(n); - for (PyObject item : iterable.asIterable()) { - objs.add(item); - } - return objs.toArray(Py.EmptyObjects); - } - - /** - * Infers the usual Jython executable name from the position of the - * jar-file returned by {@link #getJarFileName()} by replacing the - * file name with "bin/jython". This is intended as an easy fallback - * for cases where {@code sys.executable} is {@code None} due to - * direct launching via the java executable.
    - * Note that this does not necessarily return the actual executable, - * but instead infers the place where it is usually expected to be. - * Use {@code sys.executable} to get the actual executable (may be - * {@code None}. - * - * In contrast to {@link #getJarFileName()} and - * {@link #getJarFileNameFromURL(java.net.URL)} this method returns - * the path using system-specific separator characters. - * - * @return usual Jython-executable as absolute path - */ - public static String getDefaultExecutableName() { - return getDefaultBinDir()+File.separator+( - Platform.IS_WINDOWS ? "jython.exe" : "jython"); - } - - /** - * Infers the usual Jython bin-dir from the position of the jar-file - * returned by {@link #getJarFileName()} byr replacing the file name - * with "bin". This is intended as an easy fallback for cases where - * {@code sys.executable} is {@code null} due to direct launching via - * the java executable.
    - * Note that this does not necessarily return the actual bin-directory, - * but instead infers the place where it is usually expected to be. - * - * In contrast to {@link #getJarFileName()} and - * {@link #getJarFileNameFromURL(java.net.URL)} this method returns - * the path using system-specific separator characters. - * - * @return usual Jython bin-dir as absolute path - */ - public static String getDefaultBinDir() { - String jar = _getJarFileName(); - if (File.separatorChar != '/') { - jar = jar.replace('/', File.separatorChar); - } - return jar.substring(0, jar.lastIndexOf(File.separatorChar)+1)+"bin"; - } - - /** - * Utility-method to obtain the name (including absolute path) of the currently used - * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or - * jython-standalone.jar or something custom. - * - * @return the full name of the jar file containing this class, null - * if not available. - */ - public static String getJarFileName() { - String jar = _getJarFileName(); - if (File.separatorChar != '/') { - jar = jar.replace('/', File.separatorChar); - } - return jar; - } - - /** - * Utility-method to obtain the name (including absolute path) of the currently used - * jython-jar-file. Usually this is jython.jar, but can also be jython-dev.jar or - * jython-standalone.jar or something custom. - * - * Note that it does not use system-specific seperator-chars, but always '/'. - * - * @return the full name of the jar file containing this class, null - * if not available. - */ - public static String _getJarFileName() { - Class thisClass = Py.class; - String fullClassName = thisClass.getName(); - String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1); - URL url = thisClass.getResource(className + ".class"); - return getJarFileNameFromURL(url); - } - - /**exclusively used by {@link #getJarFileNameFromURL(java.net.URL)}.*/ - private static final String JAR_URL_PREFIX = "jar:file:"; - /**exclusively used by {@link #getJarFileNameFromURL(java.net.URL)}.*/ - private static final String JAR_SEPARATOR = "!"; - /**exclusively used by {@link #getJarFileNameFromURL(java.net.URL)}.*/ - private static final String VFSZIP_PREFIX = "vfszip:"; - /**exclusively used by {@link #getJarFileNameFromURL(java.net.URL)}.*/ - private static final String VFS_PREFIX = "vfs:"; - - /** - * Converts a url that points to a jar-file to the actual jar-file name. - * Note that it does not use system-specific seperator-chars, but always '/'. - */ - public static String getJarFileNameFromURL(URL url) { - String jarFileName = null; - if (url != null) { - try { - // escape plus signs, since the URLDecoder would turn them into spaces - final String plus = "\\+"; - final String escapedPlus = "__ppluss__"; - String rawUrl = url.toString(); - rawUrl = rawUrl.replaceAll(plus, escapedPlus); - String urlString = URLDecoder.decode(rawUrl, "UTF-8"); - urlString = urlString.replaceAll(escapedPlus, plus); - int jarSeparatorIndex = urlString.lastIndexOf(JAR_SEPARATOR); - if (urlString.startsWith(JAR_URL_PREFIX) && jarSeparatorIndex > 0) { - // jar:file:/install_dir/jython.jar!/org/python/core/PySystemState.class - int start = JAR_URL_PREFIX.length(); - if (Platform.IS_WINDOWS) { - start++; - } - jarFileName = urlString.substring(start, jarSeparatorIndex); - } else if (urlString.startsWith(VFSZIP_PREFIX)) { - // vfszip:/some/path/jython.jar/org/python/core/PySystemState.class - final String path = Py.class.getName().replace('.', '/'); - int jarIndex = urlString.indexOf(".jar/".concat(path)); - if (jarIndex > 0) { - jarIndex += 4; - int start = VFSZIP_PREFIX.length(); - if (Platform.IS_WINDOWS) { - // vfszip:/C:/some/path/jython.jar/org/python/core/PySystemState.class - start++; - } - jarFileName = urlString.substring(start, jarIndex); - } - } else if (urlString.startsWith(VFS_PREFIX)) { - // vfs:/some/path/jython.jar/org/python/core/PySystemState.class - final String path = Py.class.getName().replace('.', '/'); - int jarIndex = urlString.indexOf(".jar/".concat(path)); - if (jarIndex > 0) { - jarIndex += 4; - int start = VFS_PREFIX.length(); - if (Platform.IS_WINDOWS) { - // vfs:/C:/some/path/jython.jar/org/python/core/PySystemState.class - start++; - } - jarFileName = urlString.substring(start, jarIndex); - } - } - } catch (Exception e) {} - } - return jarFileName; } -//------------------------contructor-section--------------------------- +//------------------------constructor-section--------------------------- static class py2JyClassCacheItem { List> interfaces; List pyClasses; @@ -2510,17 +2605,16 @@ protected static PyObject ensureInterface(PyObject cls, Class interfce) { } /** - * Returns a Python-class that extends {@code cls} and {@code interfce}. - * If {@code cls} already extends {@code interfce}, simply {@code cls} - * is returned. Otherwise a new class is created (if not yet cached). - * It caches such classes and only creates a new one if no appropriate + * Returns a Python-class that extends {@code cls} and {@code interfce}. If {@code cls} already + * extends {@code interfce}, simply {@code cls} is returned. Otherwise a new class is created + * (if not yet cached). It caches such classes and only creates a new one if no appropriate * class was cached yet. * * @return a Python-class that extends {@code cls} and {@code interfce} */ public static synchronized PyObject javaPyClass(PyObject cls, Class interfce) { - py2JyClassCacheItem cacheItem = (py2JyClassCacheItem) - JyAttribute.getAttr(cls, JyAttribute.PYCLASS_PY2JY_CACHE_ATTR); + py2JyClassCacheItem cacheItem = (py2JyClassCacheItem) JyAttribute.getAttr(cls, + JyAttribute.PYCLASS_PY2JY_CACHE_ATTR); PyObject result; if (cacheItem == null) { result = ensureInterface(cls, interfce); @@ -2537,22 +2631,21 @@ public static synchronized PyObject javaPyClass(PyObject cls, Class interfce) } /** - * This method is a compact helper to access Python-constructors from Java. - * It creates an instance of {@code cls} and retruns it in form of - * {@code jcls}, which must be an interface. This method even works if - * {@code cls} does not extend {@code jcls} in Python-code. In that case, - * it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate - * class on the fly.
    + * This method is a compact helper to access Python-constructors from Java. It creates an + * instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface. + * This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that + * case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the + * fly. + *

    * It automatically converts {@code args} to {@link org.python.core.PyObject}s.
    - * For keyword-support use - * {@link #newJ(PyObject, Class, String[], Object...)}. + * For keyword-support use {@link #newJ(PyObject, Class, String[], Object...)}. * - * {@see #newJ(PyObject, Class, PyObject[], String[])} - * {@see #newJ(PyObject, Class, String[], Object...)} - * {@see #newJ(PyModule, Class, Object...)} - * {@see #newJ(PyModule, Class, String[], Object...)} - * {@see org.python.core.PyModule#newJ(Class, Object...)} - * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} + * @see #newJ(PyObject, Class, PyObject[], String[]) + * @see #newJ(PyObject, Class, String[], Object...) + * @see #newJ(PyModule, Class, Object...) + * @see #newJ(PyModule, Class, String[], Object...) + * @see PyModule#newJ(Class, Object...) + * @see PyModule#newJ(Class, String[], Object...) * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2567,20 +2660,20 @@ public static T newJ(PyObject cls, Class jcls, Object... args) { } /** - * This method is a compact helper to access Python-constructors from Java. - * It creates an instance of {@code cls} and retruns it in form of - * {@code jcls}, which must be an interface. This method even works if - * {@code cls} does not extend {@code jcls} in Python-code. In that case, - * it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate - * class on the fly.
    + * This method is a compact helper to access Python-constructors from Java. It creates an + * instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface. + * This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that + * case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the + * fly. + *

    * {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJ(PyObject, Class, Object...)} - * {@see #newJ(PyObject, Class, String[], Object...)} - * {@see #newJ(PyModule, Class, Object...)} - * {@see #newJ(PyModule, Class, String[], Object...)} - * {@see org.python.core.PyModule#newJ(Class, Object...)} - * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} + * @see #newJ(PyObject, Class, Object...) + * @see #newJ(PyObject, Class, String[], Object...) + * @see #newJ(PyModule, Class, Object...) + * @see #newJ(PyModule, Class, String[], Object...) + * @see PyModule#newJ(Class, Object...) + * @see PyModule#newJ(Class, String[], Object...) * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2596,21 +2689,21 @@ public static T newJ(PyObject cls, Class jcls, PyObject[] args, String[] } /** - * This method is a compact helper to access Python-constructors from Java. - * It creates an instance of {@code cls} and retruns it in form of - * {@code jcls}, which must be an interface. This method even works if - * {@code cls} does not extend {@code jcls} in Python-code. In that case, - * it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate - * class on the fly.
    + * This method is a compact helper to access Python-constructors from Java. It creates an + * instance of {@code cls} and retruns it in form of {@code jcls}, which must be an interface. + * This method even works if {@code cls} does not extend {@code jcls} in Python-code. In that + * case, it uses {@link #javaPyClass(PyObject, Class)} to create an appropriate class on the + * fly. + *

    * It automatically converts {@code args} to {@link org.python.core.PyObject}s.
    * {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJ(PyObject, Class, PyObject[], String[])} - * {@see #newJ(PyObject, Class, Object...)} - * {@see #newJ(PyModule, Class, Object...)} - * {@see #newJ(PyModule, Class, String[], Object...)} - * {@see org.python.core.PyModule#newJ(Class, Object...)} - * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} + * @see #newJ(PyObject, Class, PyObject[], String[]) + * @see #newJ(PyObject, Class, Object...) + * @see #newJ(PyModule, Class, Object...) + * @see #newJ(PyModule, Class, String[], Object...) + * @see PyModule#newJ(Class, Object...) + * @see PyModule#newJ(Class, String[], Object...) * * @param cls - the class to be instanciated * @param jcls - the Java-type to be returned @@ -2626,41 +2719,40 @@ public static T newJ(PyObject cls, Class jcls, String[] keywords, Object. } /** - * Works like {@link #newJ(PyObject, Class, Object...)}, but looks - * up the Python-class in the module-dict using the interface-name, i.e. - * {@code jcls.getSimpleName()}.
    + * Works like {@link #newJ(PyObject, Class, Object...)}, but looks up the Python-class in the + * module-dict using the interface-name, i.e. {@code jcls.getSimpleName()}. + *

    * For keywords-support use {@link #newJ(PyModule, Class, String[], Object...)}. * - * {@see #newJ(PyModule, Class, String[], Object...)} - * {@see #newJ(PyObject, Class, PyObject[], String[])} - * {@see #newJ(PyObject, Class, Object...)} - * {@see #newJ(PyObject, Class, String[], Object...)} - * {@see org.python.core.PyModule#newJ(Class, Object...)} - * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} + * @see #newJ(PyModule, Class, String[], Object...) + * @see #newJ(PyObject, Class, PyObject[], String[]) + * @see #newJ(PyObject, Class, Object...) + * @see #newJ(PyObject, Class, String[], Object...) + * @see PyModule#newJ(Class, Object...) + * @see PyModule#newJ(Class, String[], Object...) * * @param module the module containing the desired class * @param jcls Java-type of the desired clas, must have the same name * @param args constructor-arguments * @return a new instance of the desired class */ - @SuppressWarnings("unchecked") public static T newJ(PyModule module, Class jcls, Object... args) { PyObject cls = module.__getattr__(jcls.getSimpleName().intern()); return newJ(cls, jcls, args); } /** - * Works like {@link #newJ(PyObject, Class, String[], Object...)}, but looks - * up the Python-class in the module-dict using the interface-name, i.e. - * {@code jcls.getSimpleName()}.
    + * Works like {@link #newJ(PyObject, Class, String[], Object...)}, but looks up the Python-class + * in the module-dict using the interface-name, i.e. {@code jcls.getSimpleName()}. + *

    * {@code keywordss} are applied to the last {@code args} in the list. * - * {@see #newJ(PyModule, Class, Object...)} - * {@see #newJ(PyObject, Class, PyObject[], String[])} - * {@see #newJ(PyObject, Class, Object...)} - * {@see #newJ(PyObject, Class, String[], Object...)} - * {@see org.python.core.PyModule#newJ(Class, Object...)} - * {@see org.python.core.PyModule#newJ(Class, String[], Object...)} + * @see #newJ(PyModule, Class, Object...) + * @see #newJ(PyObject, Class, PyObject[], String[]) + * @see #newJ(PyObject, Class, Object...) + * @see #newJ(PyObject, Class, String[], Object...) + * @see PyModule#newJ(Class, Object...) + * @see PyModule#newJ(Class, String[], Object...) * * @param module the module containing the desired class * @param jcls Java-type of the desired class, must have the same name @@ -2668,7 +2760,6 @@ public static T newJ(PyModule module, Class jcls, Object... args) { * @param args constructor-arguments * @return a new instance of the desired class */ - @SuppressWarnings("unchecked") public static T newJ(PyModule module, Class jcls, String[] keywords, Object... args) { PyObject cls = module.__getattr__(jcls.getSimpleName().intern()); return newJ(cls, jcls, keywords, args); @@ -2714,9 +2805,14 @@ public JavaCode(PyObject func) { @Override public PyObject call(ThreadState state, PyFrame frame, PyObject closure) { - //XXX: what the heck is this? Looks like debug code, but it's - // been here a long time... - System.out.println("call #1"); + /* This should actually + * throw new UnsupportedOperationException( + * "JavaCode doesn't support call with signature "+ + * "(ThreadState state, PyFrame frame, PyObject closure)."); + * However since this would be an API-change, for 2.7 series we just warn. + */ + Py.warning(Py.RuntimeWarning, "JavaCode doesn't support call with signature "+ + "(ThreadState state, PyFrame frame, PyObject closure)."); return Py.None; } diff --git a/src/org/python/core/Py2kBuffer.java b/src/org/python/core/Py2kBuffer.java index 0c5ec9552..6fbf30608 100644 --- a/src/org/python/core/Py2kBuffer.java +++ b/src/org/python/core/Py2kBuffer.java @@ -41,7 +41,7 @@ public class Py2kBuffer extends PySequence implements BufferProtocol { * action performed obtains a new one and releases it. (Major difference from * memoryview.) Note that when size=-1 is given, the buffer reflects * the changing size of the underlying object. - * + * * @param object the object on which this is to be a buffer. * @param offset into the array exposed by the object (0 for start). * @param size of the slice or -1 for all of the object. @@ -72,14 +72,14 @@ public Py2kBuffer(BufferProtocol object, int offset, int size) { /** * Every action on the buffer must obtain a new {@link PyBuffer} reflecting (this * buffer's slice of) the contents of the backing object. - * + * * @return a PyBuffer onto the specified slice. */ private PyBuffer getBuffer() { /* - * Ask for a simple one-dimensional byte view (not requiring strides, indirect, etc.) from - * the object, as we cannot deal with other navigation. Ask for read access. If the object - * is writable, the PyBuffer will be writable, but we won't write to it. + * Ask for a simple one-dimensional byte view from the object, as we cannot deal with more + * complex navigation. Ask for read access. If the object is writable, the PyBuffer will be + * writable, but we won't write to it. */ final int flags = PyBUF.SIMPLE; PyBuffer buf = object.getBuffer(flags); @@ -120,7 +120,7 @@ private PyBuffer getBuffer() { * except in the case of a {@link PyUnicode}, which will be converted to a {@link PyString} * according to Py2k semantics, equivalent to a UTF16BE encoding to bytes (for Py2k * compatibility). - * + * * @param obj the object to access. * @return PyObject supporting {@link BufferProtocol}, if not null. */ @@ -186,25 +186,30 @@ public int __len__() { @Override public PyString __repr__() { - String fmt = ""; - String ret = String.format(fmt, Py.idstr((PyObject)object), size, offset, Py.idstr(this)); + return buffer___repr__(); + } + + @ExposedMethod(doc = BuiltinDocs.buffer___repr___doc) + final PyString buffer___repr__() { + String fmt = ""; + String ret = String.format(fmt, Py.idstr((PyObject) object), size, offset, Py.idstr(this)); return new PyString(ret); } @Override public PyString __str__() { - PyBuffer buf = getBuffer(); - try { - if (buf instanceof BaseBuffer) { - // In practice, it always is - return new PyString(buf.toString()); - } else { - // But just in case ... - String s = StringUtil.fromBytes(buf); - return new PyString(s); - } - } finally { - buf.release(); + return buffer___str__(); + } + + @ExposedMethod(doc = BuiltinDocs.buffer___str___doc) + final PyString buffer___str__() { + return new PyString(toString()); + } + + @Override + public String toString() { + try (PyBuffer buf = getBuffer()) { + return buf.toString(); } } @@ -292,7 +297,7 @@ final PyObject buffer___rmul__(PyObject o) { * conventions, left-to-right (low to high index). Zero bytes are significant, even at the end * of the array: [65,66,67]<"ABC\u0000", for example and [] is less * than every non-empty b, while []=="". - * + * * @param a left-hand wrapped array in the comparison * @param b right-hand wrapped object in the comparison * @return 1, 0 or -1 as a>b, a==b, or a<b respectively @@ -333,7 +338,7 @@ private static int compare(PyBuffer a, PyBuffer b) { /** * Comparison function between this buffer and any other object. The inequality * comparison operators are based on this. - * + * * @param b * @return 1, 0 or -1 as this>b, this==b, or this<b respectively, or -2 if the comparison is * not implemented @@ -377,7 +382,7 @@ private int buffer_cmp(PyObject b) { * Fail-fast comparison function between byte array types and any other object, for when the * test is only for equality. The inequality comparison operators __eq__ and * __ne__ are based on this. - * + * * @param b * @return 0 if this==b, or +1 or -1 if this!=b, or -2 if the comparison is not implemented */ @@ -487,7 +492,7 @@ public PyBuffer getBuffer(int flags) { * Gets the indexed element of the buffer as a one byte string. This is an * extension point called by PySequence in its implementation of {@link #__getitem__}. It is * guaranteed by PySequence that the index is within the bounds of the buffer. - * + * * @param index index of the element to get. * @return one-character string formed from the byte at the index */ @@ -505,7 +510,7 @@ protected PyString pyget(int index) { /** * Returns a slice of elements from this sequence as a PyString. - * + * * @param start the position of the first element. * @param stop one more than the position of the last element. * @param step the step size. @@ -530,7 +535,7 @@ protected synchronized PyString getslice(int start, int stop, int step) { /** * buffer*int represents repetition in Python, and returns a str ( * bytes) object. - * + * * @param count the number of times to repeat this. * @return a PyString repeating this buffer (as a str) that many times */ @@ -553,11 +558,11 @@ protected synchronized PyString repeat(int count) { * {@link #__setitem__} It is guaranteed by PySequence that the index is within the bounds of * the buffer. Any other clients calling pyset(int, PyObject) must make * the same guarantee. - * + * * @param index index of the element to set. * @param value to set this element to, regarded as a buffer of length one unit. - * @throws PyException(AttributeError) if value cannot be converted to an integer - * @throws PyException(ValueError) if value<0 or value>255 + * @throws PyException {@code AttributeError} if value cannot be converted to an integer + * @throws PyException {@code ValueError} if value<0 or value%gt;255 */ @Override public synchronized void pyset(int index, PyObject value) throws PyException { @@ -585,13 +590,13 @@ public synchronized void pyset(int index, PyObject value) throws PyException { * Sets the given range of elements according to Python slice assignment semantics. If the step * size is one, it is a simple slice and the operation is equivalent to replacing that slice, * with the value, accessing the value via the buffer protocol. - * + * *

          * a = bytearray(b'abcdefghijklmnopqrst')
          * m = buffer(a)
          * m[2:7] = "ABCDE"
          * 
    - * + * * Results in a=bytearray(b'abABCDEhijklmnopqrst'). *

    * If the step size is one, but stop-start does not match the length of the right-hand-side a @@ -600,14 +605,14 @@ public synchronized void pyset(int index, PyObject value) throws PyException { * If the step size is not one, and start!=stop, the slice defines a certain number of elements * to be replaced. This function is not available in Python 2.7 (but it is in Python 3.3). *

    - * + * *

          * a = bytearray(b'abcdefghijklmnopqrst')
          * a[2:12:2] = iter( [65, 66, 67, long(68), "E"] )
          * 
    - * + * * Results in a=bytearray(b'abAdBfChDjElmnopqrst') in Python 3.3. - * + * * @param start the position of the first element. * @param stop one more than the position of the last element. * @param step the step size. diff --git a/src/org/python/core/PyArray.java b/src/org/python/core/PyArray.java index 17f5b704b..3db5f7442 100644 --- a/src/org/python/core/PyArray.java +++ b/src/org/python/core/PyArray.java @@ -13,8 +13,8 @@ import java.nio.ByteBuffer; import org.python.core.buffer.BaseBuffer; +import org.python.core.buffer.SimpleBuffer; import org.python.core.buffer.SimpleStringBuffer; -import org.python.core.buffer.SimpleWritableBuffer; import org.python.core.util.ByteSwapper; import org.python.core.util.StringUtil; import org.python.expose.ExposedGet; @@ -398,7 +398,7 @@ final PyObject array___add__(PyObject other) { PyArray otherArr = (PyArray)other; if (!otherArr.typecode.equals(this.typecode)) { throw Py.TypeError("can only append arrays of the same type, expected '" + this.type - + ", found " + otherArr.type); + + "', found '" + otherArr.type + "'"); } PyArray ret = new PyArray(this); ret.delegate.appendArray(otherArr.delegate.copyArray()); @@ -600,9 +600,8 @@ public Object clone() { /** * Converts a character code for the array type to a Java Class. - *

    - * The following character codes and their native types are supported:
    *

  • + * * * * @@ -1285,9 +1284,8 @@ public Object getArray() throws PyIgnoreMethodTag { * memory this value is the minimum number of bytes required to store the type. *

    * This method is used by other methods to define read/write quanta from strings and streams. - *

    - * Values returned are:
    *

    Supported character codes and their native types
    Type codenative type
    + * * * * @@ -2066,40 +2064,46 @@ protected Object createArray(int size) { *

    * The {@link PyBuffer} returned from this method is a one-dimensional array of single byte * items that allows modification of the object state. The existence of this export prohibits - * resizing the byte array. This prohibition is not only on the consumer of the view but - * extends to any other operations, such as any kind or insertion or deletion. + * resizing the array. This prohibition is not only on the consumer of the view but extends + * to operations on the underlying array, such as {@link #insert(int, PyObject)} or + * {@link #pop()}. */ @Override public synchronized PyBuffer getBuffer(int flags) { - // If we have already exported a buffer it may still be available for re-use - BaseBuffer pybuf = getExistingBuffer(flags); - - if (pybuf == null) { - // No existing export we can re-use: create a new one - if ("b".equals(typecode)) { - // This is byte data, so we are within the state of the art - byte[] storage = (byte[])data; - int size = delegate.getSize(); - pybuf = new SimpleWritableBuffer(flags, this, storage, 0, size); - } else if ((flags & PyBUF.WRITABLE) == 0) { - // As the client only intends to read, fake the answer with a String - pybuf = new SimpleStringBuffer(flags, this, tostring()); - } else { - // For the time being ... - throw Py.NotImplementedError("only array('b') can export a writable buffer"); + if ((flags & ~PyBUF.WRITABLE) == PyBUF.SIMPLE) { + // Client requests a flat byte-oriented read-view, typically from buffer(a). + + // If we have already exported a buffer it may still be available for re-use + BaseBuffer pybuf = getExistingBuffer(flags); + + if (pybuf == null) { + // No existing export we can re-use: create a new one + if ("b".equals(typecode)) { + // This is byte data, so we can export directly + byte[] storage = (byte[]) data; + int size = delegate.getSize(); + pybuf = new SimpleBuffer(flags, this, storage, 0, size); + } else { + // As the client only intends to read, fake the answer with a String + pybuf = new SimpleStringBuffer(flags, this, tostring()); + } + // Hold a reference for possible re-use + export = new WeakReference(pybuf); } - // Hold a reference for possible re-use - export = new WeakReference(pybuf); - } - return pybuf; + return pybuf; + + } else { + // Client request goes beyond Python 2 capability, typically from memoryview(a). + throw new ClassCastException("'array' supports only a byte-buffer view"); + } } /** * Try to re-use an existing exported buffer, or return null if we can't. * - * @throws PyException (BufferError) if the the flags are incompatible with the buffer + * @throws PyException {@code BufferError} if the the flags are incompatible with the buffer */ private BaseBuffer getExistingBuffer(int flags) throws PyException { BaseBuffer pybuf = null; @@ -2123,7 +2127,7 @@ private BaseBuffer getExistingBuffer(int flags) throws PyException { * Test to see if the array may be resized and raise a BufferError if not. This must be called * by the implementation of any operation that changes the number of elements in the array. * - * @throws PyException (BufferError) if there are buffer exports preventing a resize + * @throws PyException {@code BufferError} if there are buffer exports preventing a resize */ private void resizeCheck() throws PyException { if (export != null) { diff --git a/src/org/python/core/PyArrayDerived.java b/src/org/python/core/PyArrayDerived.java index fc32157da..8e08f8068 100644 --- a/src/org/python/core/PyArrayDerived.java +++ b/src/org/python/core/PyArrayDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyBUF.java b/src/org/python/core/PyBUF.java index 95f498118..86753e667 100644 --- a/src/org/python/core/PyBUF.java +++ b/src/org/python/core/PyBUF.java @@ -2,22 +2,22 @@ /** * This interface provides a base for the key interface of the buffer API, {@link PyBuffer}, - * including symbolic constants used by the consumer of a PyBuffer to specify its + * including symbolic constants used by the consumer of a {@code PyBuffer} to specify its * requirements and assumptions. The Jython buffer API emulates the CPython buffer API. There are - * two reasons for separating parts of PyBuffer into this interface: + * two reasons for separating parts of {@code PyBuffer} into this interface: *

    - * It is unlikely any classes would implement PyBUF, except indirectly through other + * It is unlikely any classes would implement {@code PyBUF}, except indirectly through other * interfaces. Users of the Jython buffer API can mostly overlook the distinction and just use - * PyBuffer. + * {@code PyBuffer}. */ public interface PyBUF { @@ -29,8 +29,8 @@ public interface PyBUF { boolean isReadonly(); /** - * The number of dimensions to the buffer. This number is the length of the shape - * array. The actual storage may be a linear array, but this is the number of dimensions in the + * The number of dimensions to the buffer. This number is the length of the {@code shape} array. + * The actual storage may be a linear array, but this is the number of dimensions in the * interpretation that the exporting object gives the data. * * @return number of dimensions @@ -43,8 +43,8 @@ public interface PyBUF { * size in "items". An item is the amount of buffer content addressed by one index or set of * indices. In the simplest case an item is a single unit (byte), and there is one dimension. In * complex cases, the array is multi-dimensional, and the item at each location is multi-unit - * (multi-byte). The consumer must not modify this array. A valid shape array is - * always returned (difference from CPython). + * (multi-byte). The consumer must not modify this array. A valid {@code shape} array is always + * returned (difference from CPython). * * @return the dimensions of the buffer as an array */ @@ -58,20 +58,20 @@ public interface PyBUF { int getItemsize(); /** - * The total number of bytes represented by the view, which will be the product of the elements of the - * shape array, and the item size in bytes. + * The total number of bytes represented by the view, which will be the product of the elements + * of the {@code shape} array, and the item size in bytes. * * @return the total number of bytes represented. */ int getLen(); /** - * The strides array gives the distance in the storage array between adjacent items - * (in each dimension). In the rawest parts of the buffer API, the consumer of the buffer is - * able to navigate the exported storage. The "strides" array is part of the support for - * interpreting the buffer as an n-dimensional array of items. It provides the coefficients of - * the "addressing polynomial". (More on this in the CPython documentation.) The consumer must - * not modify this array. A valid strides array is always returned (difference from + * The {@code strides} array gives the distance in the storage array between adjacent items (in + * each dimension). In the rawest parts of the buffer API, the consumer of the buffer is able to + * navigate the exported storage. The "strides" array is part of the support for interpreting + * the buffer as an n-dimensional array of items. It provides the coefficients of the + * "addressing polynomial". (More on this in the CPython documentation.) The consumer must not + * modify this array. A valid {@code strides} array is always returned (difference from * CPython). * * @return the distance in the storage array between adjacent items (in each dimension) @@ -79,15 +79,15 @@ public interface PyBUF { int[] getStrides(); /** - * The suboffsets array is a further part of the support for interpreting the - * buffer as an n-dimensional array of items, where the array potentially uses indirect - * addressing (like a real Java array of arrays, in fact). This is only applicable when there is - * more than 1 dimension, and it works in conjunction with the strides array. (More - * on this in the CPython documentation.) When used, suboffsets[k] is an integer - * index, not a byte offset as in CPython. The consumer must not modify this array. When not - * needed for navigation null is returned (as in CPython). + * The {@code suboffsets} array is a further part of the support for interpreting the buffer as + * an n-dimensional array of items, where the array potentially uses indirect addressing (like a + * real Java array of arrays, in fact). This is only applicable when there is more than 1 + * dimension, and it works in conjunction with the {@code strides} array. (More on this in the + * CPython documentation.) When used, {@code suboffsets[k]} is an integer index, not a byte + * offset as in CPython. The consumer must not modify this array. When not needed for navigation + * {@code null} is returned (as in CPython). * - * @return suboffsets array or null if not necessary for navigation + * @return suboffsets array or {@code null} if not necessary for navigation */ int[] getSuboffsets(); @@ -108,53 +108,53 @@ public interface PyBUF { static final int MAX_NDIM = 64; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it expects to write to the buffer contents. getBuffer will raise an + * specify that it expects to write to the buffer contents. {@code getBuffer} will raise an * exception if the exporter's buffer cannot meet this requirement. */ static final int WRITABLE = 0x0001; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to * specify that it assumes a simple one-dimensional organisation of the exported storage with - * item size of one. getBuffer will raise an exception if the consumer sets this - * flag and the exporter's buffer cannot be navigated that simply. + * item size of one. {@code getBuffer} will raise an exception if the consumer sets this flag + * and the exporter cannot represent itself as byte array data. */ static final int SIMPLE = 0; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it requires {@link PyBuffer#getFormat()} to return a String - * indicating the type of the unit. This exists for compatibility with CPython, as in Jython the - * format is always provided by getFormat(). + * specify that it requires {@link PyBuffer#getFormat()} to return a {@code String} indicating + * the type of the unit. This exists for compatibility with CPython, as in Jython the format is + * always provided by {@code getFormat()}. */ static final int FORMAT = 0x0004; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to * specify that it is prepared to navigate the buffer as multi-dimensional using the - * shape array. getBuffer will raise an exception if consumer does not - * specify the flag but the exporter's buffer cannot be navigated without taking into account - * its multiple dimensions. + * {@code shape} array. {@code getBuffer} will raise an exception if consumer does not specify + * the flag but the exporter's buffer cannot be navigated without taking into account its + * multiple dimensions. */ static final int ND = 0x0008; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it expects to use the strides array. getBuffer will - * raise an exception if consumer does not specify the flag but the exporter's buffer cannot be - * navigated without using the strides array. + * specify that it expects to use the {@code strides} array. {@code getBuffer} will raise an + * exception if consumer does not specify the flag but the exporter's buffer cannot be navigated + * without using the {@code strides} array. */ static final int STRIDES = 0x0010 | ND; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it will assume C-order organisation of the items. getBuffer will - * raise an exception if the exporter's buffer is not C-ordered. C_CONTIGUOUS - * implies STRIDES. + * specify that it will assume C-order organisation of the items. {@code getBuffer} will raise + * an exception if the exporter's buffer is not C-ordered. {@code C_CONTIGUOUS} implies + * {@code STRIDES}. */ // It is possible this should have been (0x20|ND) expressing the idea that C-order addressing // will be assumed *instead of* using a strides array. static final int C_CONTIGUOUS = 0x0020 | STRIDES; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it will assume Fortran-order organisation of the items. getBuffer - * will raise an exception if the exporter's buffer is not Fortran-ordered. - * F_CONTIGUOUS implies STRIDES. + * specify that it will assume Fortran-order organisation of the items. {@code getBuffer} will + * raise an exception if the exporter's buffer is not Fortran-ordered. {@code F_CONTIGUOUS} + * implies {@code STRIDES}. */ static final int F_CONTIGUOUS = 0x0040 | STRIDES; /** @@ -162,55 +162,53 @@ public interface PyBUF { * specify that it will assume a contiguous organisation of the items, but will enquire which * organisation it actually is. * - * getBuffer will raise an exception if the exporter's buffer is not contiguous. - * ANY_CONTIGUOUS implies STRIDES. + * {@code getBuffer} will raise an exception if the exporter's buffer is not contiguous. + * {@code ANY_CONTIGUOUS} implies {@code STRIDES}. */ // Further CPython strangeness since it uses the strides array to answer the enquiry. static final int ANY_CONTIGUOUS = 0x0080 | STRIDES; /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to - * specify that it understands the suboffsets array. getBuffer will - * raise an exception if consumer does not specify the flag but the exporter's buffer cannot be - * navigated without understanding the suboffsets array. INDIRECT - * implies STRIDES. + * specify that it understands the {@code suboffsets} array. {@code getBuffer} will raise an + * exception if consumer does not specify the flag but the exporter's buffer cannot be navigated + * without understanding the {@code suboffsets} array. {@code INDIRECT} implies {@code STRIDES}. */ static final int INDIRECT = 0x0100 | STRIDES; /** - * Equivalent to (ND | WRITABLE) + * Equivalent to {@code (ND | WRITABLE)} */ static final int CONTIG = ND | WRITABLE; /** - * Equivalent to ND + * Equivalent to {@code ND} */ static final int CONTIG_RO = ND; /** - * Equivalent to (STRIDES | WRITABLE) + * Equivalent to {@code (STRIDES | WRITABLE)} */ static final int STRIDED = STRIDES | WRITABLE; /** - * Equivalent to STRIDES + * Equivalent to {@code STRIDES} */ static final int STRIDED_RO = STRIDES; /** - * Equivalent to (STRIDES | WRITABLE | FORMAT) + * Equivalent to {@code (STRIDES | WRITABLE | FORMAT)} */ static final int RECORDS = STRIDES | WRITABLE | FORMAT; /** - * Equivalent to (STRIDES | FORMAT) + * Equivalent to {@code (STRIDES | FORMAT)} */ static final int RECORDS_RO = STRIDES | FORMAT; /** - * Equivalent to (INDIRECT | WRITABLE | FORMAT). Also use this in the request if - * you plan only to use the fully-encapsulated API (byteAt, storeAt, - * copyTo, copyFrom, etc.), without ever calling - * {@link PyBuffer#getNIOByteBuffer()} or using {@link PyBuffer#Pointer()}. + * Equivalent to {@code (INDIRECT | WRITABLE | FORMAT)}. Also use this in the request if you + * plan only to use the fully-encapsulated API ({@code byteAt}, {@code storeAt}, {@code copyTo}, + * {@code copyFrom}, etc.), without ever calling {@link PyBuffer#getNIOByteBuffer()} or using + * {@link PyBuffer.Pointer}. */ static final int FULL = INDIRECT | WRITABLE | FORMAT; /** - * Equivalent to (INDIRECT | FORMAT). Also use this in the request if you plan only - * to use the fully-encapsulated API (byteAt, copyTo, etc.), read - * only, without ever calling {@link PyBuffer#getNIOByteBuffer()} or using - * {@link PyBuffer#Pointer()}. + * Equivalent to {@code (INDIRECT | FORMAT)}. Also use this in the request if you plan only to + * use the fully-encapsulated API ({@code byteAt}, {@code copyTo}, etc.), read only, without + * ever calling {@link PyBuffer#getNIOByteBuffer()} or using {@link PyBuffer.Pointer}. */ static final int FULL_RO = INDIRECT | FORMAT; @@ -219,43 +217,42 @@ public interface PyBUF { /** * A constant used by the consumer in its call to {@link BufferProtocol#getBuffer(int)} to * specify that it expects to access the buffer contents directly as an array (rather than - * through the purely abstract part of the API). getBuffer will raise an exception - * if the exporter cannot expose its storage as Java array. + * through the purely abstract part of the API). {@code getBuffer} will raise an exception if + * the exporter cannot expose its storage as Java array. */ // XXX Pending: @Deprecated - static final int AS_ARRAY = 0x10000000; + static final int AS_ARRAY = 0x10000000; /* Constants for readability, not standard for CPython */ /** - * Field mask, used as in if ((flags&NAVIGATION) == STRIDES) .... The importance of - * the subset of flags defined by this mask is not so much in their "navigational" character as - * in the way they are treated in a buffer request. + * Field mask, used as in {@code if ((flags&NAVIGATION) == STRIDES) ...}. The importance of the + * subset of flags defined by this mask is not so much in their "navigational" character as in + * the way they are treated in a buffer request. *

    - * The NAVIGATION set are used to specify which navigation arrays the consumer will - * use, and therefore the consumer must ask for all those necessary to use the buffer - * successfully (which is a function of the buffer's actual type). Asking for extra ones is not - * an error, since all are supplied (in Jython): asking for too few is an error. + * The {@code NAVIGATION} set are used to specify which navigation arrays the consumer will use, + * and therefore the consumer must ask for all those necessary to use the buffer successfully + * (which is a function of the buffer's actual type). Asking for extra ones is not an error, + * since all are supplied (in Jython): asking for too few is an error. *

    - * Flags outside the NAVIGATION set, work the other way round. Asking for one the - * buffer cannot match is an error: not asking for a feature the buffer does not have is an - * error. + * Flags outside the {@code NAVIGATION} set, work the other way round. Asking for one the buffer + * cannot match is an error: not asking for a feature the buffer does not have is an error. */ static final int NAVIGATION = SIMPLE | ND | STRIDES | INDIRECT; /** * A constant used by the exporter in processing {@link BufferProtocol#getBuffer(int)} to check * for assumed C-order organisation of the items. - * C_CONTIGUOUS = IS_C_CONTIGUOUS | STRIDES. + * {@code C_CONTIGUOUS = IS_C_CONTIGUOUS | STRIDES}. */ static final int IS_C_CONTIGUOUS = C_CONTIGUOUS & ~STRIDES; /** * A constant used by the exporter in processing {@link BufferProtocol#getBuffer(int)} to check * for assumed C-order Fortran-order organisation of the items. - * F_CONTIGUOUS = IS_F_CONTIGUOUS | STRIDES. + * {@code F_CONTIGUOUS = IS_F_CONTIGUOUS | STRIDES}. */ static final int IS_F_CONTIGUOUS = F_CONTIGUOUS & ~STRIDES; /** - * Field mask, used as in if ((flags&CONTIGUITY)== ... ) .... + * Field mask, used as in if {@code ((flags&CONTIGUITY)== ... ) ...}. */ static final int CONTIGUITY = (C_CONTIGUOUS | F_CONTIGUOUS | ANY_CONTIGUOUS) & ~STRIDES; } diff --git a/src/org/python/core/PyBaseCode.java b/src/org/python/core/PyBaseCode.java index 16f472e2b..317c91ef2 100644 --- a/src/org/python/core/PyBaseCode.java +++ b/src/org/python/core/PyBaseCode.java @@ -4,7 +4,6 @@ */ package org.python.core; -import org.python.modules._systemrestart; import com.google.common.base.CharMatcher; public abstract class PyBaseCode extends PyCode { @@ -103,21 +102,16 @@ public PyObject call(ThreadState ts, PyFrame frame, PyObject closure) { ts.exception = previous_exception; ts.frame = ts.frame.f_back; - - // Check for interruption, which is used for restarting the interpreter - // on Jython - if (ts.getSystemState()._systemRestart && Thread.currentThread().isInterrupted()) { - throw new PyException(_systemrestart.SystemRestart); - } return ret; } public PyObject call(ThreadState state, PyObject globals, PyObject[] defaults, PyObject closure) { - if (co_argcount != 0 || varargs || varkwargs) + if (co_argcount != 0 || varargs || varkwargs) { return call(state, Py.EmptyObjects, Py.NoKeywords, globals, defaults, closure); + } PyFrame frame = new PyFrame(this, globals); if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) { return new PyGenerator(frame, closure); @@ -128,9 +122,10 @@ public PyObject call(ThreadState state, PyObject globals, PyObject[] defaults, public PyObject call(ThreadState state, PyObject arg1, PyObject globals, PyObject[] defaults, PyObject closure) { - if (co_argcount != 1 || varargs || varkwargs) + if (co_argcount != 1 || varargs || varkwargs) { return call(state, new PyObject[] {arg1}, Py.NoKeywords, globals, defaults, closure); + } PyFrame frame = new PyFrame(this, globals); frame.f_fastlocals[0] = arg1; if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) { @@ -142,9 +137,10 @@ public PyObject call(ThreadState state, PyObject arg1, PyObject globals, PyObjec public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject globals, PyObject[] defaults, PyObject closure) { - if (co_argcount != 2 || varargs || varkwargs) + if (co_argcount != 2 || varargs || varkwargs) { return call(state, new PyObject[] {arg1, arg2}, Py.NoKeywords, globals, defaults, closure); + } PyFrame frame = new PyFrame(this, globals); frame.f_fastlocals[0] = arg1; frame.f_fastlocals[1] = arg2; @@ -158,9 +154,10 @@ public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject a PyObject globals, PyObject[] defaults, PyObject closure) { - if (co_argcount != 3 || varargs || varkwargs) + if (co_argcount != 3 || varargs || varkwargs) { return call(state, new PyObject[] {arg1, arg2, arg3}, Py.NoKeywords, globals, defaults, closure); + } PyFrame frame = new PyFrame(this, globals); frame.f_fastlocals[0] = arg1; frame.f_fastlocals[1] = arg2; @@ -170,14 +167,15 @@ public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject a } return call(state, frame, closure); } - + @Override public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject globals, PyObject[] defaults, PyObject closure) { - if (co_argcount != 4 || varargs || varkwargs) + if (co_argcount != 4 || varargs || varkwargs) { return call(state, new PyObject[]{arg1, arg2, arg3, arg4}, Py.NoKeywords, globals, defaults, closure); + } PyFrame frame = new PyFrame(this, globals); frame.f_fastlocals[0] = arg1; frame.f_fastlocals[1] = arg2; @@ -256,7 +254,7 @@ public PyObject call(ThreadState state, PyObject args[], String kws[], PyObject co_name, Py.newUnicode(keyword).encode("ascii", "replace"))); } - if (CharMatcher.ASCII.matchesAllOf(keyword)) { + if (CharMatcher.ascii().matchesAllOf(keyword)) { kwdict.__setitem__(keyword, value); } else { kwdict.__setitem__(Py.newUnicode(keyword), value); @@ -309,8 +307,10 @@ public PyObject call(ThreadState state, PyObject args[], String kws[], PyObject } public String toString() { - return String.format("", - co_name, Py.idstr(this), co_filename, co_firstlineno); + // Result must be convertible to a str (for __repr__()), but let's make it fully printable. + String filename = PyString.encode_UnicodeEscape(co_filename, '"'); + return String.format("", + co_name, Py.idstr(this), filename, co_firstlineno); } protected abstract PyObject interpret(PyFrame f, ThreadState ts); diff --git a/src/org/python/core/PyBaseException.java b/src/org/python/core/PyBaseException.java index 57d7573bb..139d52f72 100644 --- a/src/org/python/core/PyBaseException.java +++ b/src/org/python/core/PyBaseException.java @@ -96,7 +96,7 @@ public PyObject __setstate__(PyObject state) { @ExposedMethod(doc = BuiltinDocs.BaseException___setstate___doc) final PyObject BaseException___setstate__(PyObject state) { if (state != Py.None) { - if (!(state instanceof PyStringMap) && !(state instanceof PyDictionary)) { + if (!(state instanceof AbstractDict)) { throw Py.TypeError("state is not a dictionary"); } for (PyObject key : state.asIterable()) { @@ -169,12 +169,17 @@ public PyString __str__() { @ExposedMethod(doc = BuiltinDocs.BaseException___str___doc) final PyString BaseException___str__() { switch (args.__len__()) { - case 0: - return Py.EmptyString; - case 1: - return args.__getitem__(0).__str__(); - default: - return args.__str__(); + case 0: + return Py.EmptyString; + case 1: + PyObject arg = args.__getitem__(0); + if (arg instanceof PyString) { + return (PyString)arg; + } else { + return arg.__str__(); + } + default: + return args.__str__(); } } diff --git a/src/org/python/core/PyBaseString.java b/src/org/python/core/PyBaseString.java index df924cea3..adf323fe2 100644 --- a/src/org/python/core/PyBaseString.java +++ b/src/org/python/core/PyBaseString.java @@ -6,11 +6,26 @@ * base class for jython strings. */ @ExposedType(name = "basestring", base = PyObject.class, doc = BuiltinDocs.basestring_doc) -public abstract class PyBaseString extends PySequence { +public abstract class PyBaseString extends PySequence implements CharSequence { public static final PyType TYPE = PyType.fromClass(PyBaseString.class); protected PyBaseString(PyType type) { super(type); } + + @Override + public char charAt(int index) { + return toString().charAt(index); + } + + @Override + public int length() { + return toString().length(); + } + + @Override + public CharSequence subSequence(int start, int end) { + return toString().subSequence(start, end); + } } diff --git a/src/org/python/core/PyBeanEventProperty.java b/src/org/python/core/PyBeanEventProperty.java index bd42bb46d..8ccdf2db5 100644 --- a/src/org/python/core/PyBeanEventProperty.java +++ b/src/org/python/core/PyBeanEventProperty.java @@ -114,7 +114,7 @@ private synchronized Object getAdapter(Object self) { return adapter; } try { - adapter = adapterClass.newInstance(); + adapter = adapterClass.getDeclaredConstructor().newInstance(); addMethod.invoke(self, adapter); } catch (Exception e) { throw Py.JavaError(e); diff --git a/src/org/python/core/PyBuffer.java b/src/org/python/core/PyBuffer.java index 9cdc7732f..bda1a17a2 100644 --- a/src/org/python/core/PyBuffer.java +++ b/src/org/python/core/PyBuffer.java @@ -41,7 +41,7 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Return the byte indexed from a one-dimensional buffer with item size one. This is part of the * fully-encapsulated API: the buffer implementation exported takes care of navigating the * structure of the buffer. Results are undefined where the number of dimensions is not one or - * if itemsize>1. + * if itemsize>1. * * @param index to retrieve from * @return the item at index, which is a byte @@ -52,10 +52,10 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Return the unsigned byte value indexed from a one-dimensional buffer with item size one. This * is part of the fully-encapsulated API: the exporter takes care of navigating the structure of * the buffer. Results are undefined where the number of dimensions is not one or if - * itemsize>1. + * itemsize>1. * * @param index to retrieve from - * @return the item at index, treated as an unsigned byte, =0xff & byteAt(index) + * @return the item at index, treated as an unsigned byte, {@code =0xff & byteAt(index)} */ int intAt(int index) throws IndexOutOfBoundsException; @@ -63,7 +63,7 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Store the given byte at the indexed location in of a one-dimensional buffer with item size * one. This is part of the fully-encapsulated API: the buffer implementation exported takes * care of navigating the structure of the buffer. Results are undefined where the number of - * dimensions is not one or if itemsize>1. + * dimensions is not one or if itemsize>1. * * @param value to store * @param index to location @@ -76,7 +76,7 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Return the byte indexed from an N-dimensional buffer with item size one. This is part of the * fully-encapsulated API: the buffer implementation exported takes care of navigating the * structure of the buffer. The indices must be correct in number and range for the array shape. - * Results are undefined where itemsize>1. + * Results are undefined where itemsize>1. * * @param indices specifying location to retrieve from * @return the item at location, which is a byte @@ -87,10 +87,10 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Return the unsigned byte value indexed from an N-dimensional buffer with item size one. This * is part of the fully-encapsulated API: the buffer implementation exported takes care of * navigating the structure of the buffer. The indices must be correct in number and range for - * the array shape. Results are undefined where itemsize>1. + * the array shape. Results are undefined where itemsize>1. * * @param indices specifying location to retrieve from - * @return the item at location, treated as an unsigned byte, =0xff & byteAt(index) + * @return the item at location, treated as an unsigned byte, {@code =0xff & byteAt(index)} */ int intAt(int... indices) throws IndexOutOfBoundsException; @@ -98,7 +98,7 @@ public interface PyBuffer extends PyBUF, BufferProtocol, AutoCloseable { * Store the given byte at the indexed location in of an N-dimensional buffer with item size * one. This is part of the fully-encapsulated API: the exporter takes care of navigating the * structure of the buffer. The indices must be correct in number and range for the array shape. - * Results are undefined where itemsize>1. + * Results are undefined where itemsize>1. * * @param value to store * @param indices specifying location to store at @@ -145,7 +145,7 @@ void copyTo(int srcIndex, byte[] dest, int destPos, int count) // mimic arra * @param destIndex starting item-index in the destination (i.e. this) * @param count number of items to copy in * @throws IndexOutOfBoundsException if access out of bounds in source or destination - * @throws PyException (TypeError) if read-only buffer + * @throws PyException {@code TypeError} if read-only buffer */ void copyFrom(byte[] src, int srcPos, int destIndex, int count) // mimic arraycopy args throws IndexOutOfBoundsException, PyException; @@ -157,7 +157,7 @@ void copyFrom(byte[] src, int srcPos, int destIndex, int count) // mimic arra * * @param src source buffer * @throws IndexOutOfBoundsException if access out of bounds in source or destination - * @throws PyException (TypeError) if read-only buffer + * @throws PyException {@code TypeError} if read-only buffer */ void copyFrom(PyBuffer src) throws IndexOutOfBoundsException, PyException; diff --git a/src/org/python/core/PyBuiltinMethodNarrow.java b/src/org/python/core/PyBuiltinMethodNarrow.java index 548125463..4914f3a0a 100644 --- a/src/org/python/core/PyBuiltinMethodNarrow.java +++ b/src/org/python/core/PyBuiltinMethodNarrow.java @@ -9,7 +9,7 @@ protected PyBuiltinMethodNarrow(String name) { } /** - * Creates a method for the name that takes exactly numArgs arguments. + * Creates a method for the name that takes exactly numArgs arguments. */ protected PyBuiltinMethodNarrow(String name, int numArgs) { this(name, numArgs, numArgs); @@ -31,6 +31,7 @@ protected PyBuiltinMethodNarrow(PyType type, PyObject self, Info info) { super(type, self, info); } + @Override public PyObject __call__(PyObject[] args, String[] keywords) { if(keywords.length != 0) { throw info.unexpectedCall(args.length, true); @@ -38,6 +39,7 @@ public PyObject __call__(PyObject[] args, String[] keywords) { return __call__(args); } + @Override public PyObject __call__(PyObject[] args) { switch(args.length){ case 0: @@ -55,22 +57,27 @@ public PyObject __call__(PyObject[] args) { } } + @Override public PyObject __call__() { throw info.unexpectedCall(0, false); } + @Override public PyObject __call__(PyObject arg0) { throw info.unexpectedCall(1, false); } + @Override public PyObject __call__(PyObject arg0, PyObject arg1) { throw info.unexpectedCall(2, false); } + @Override public PyObject __call__(PyObject arg0, PyObject arg1, PyObject arg2) { throw info.unexpectedCall(3, false); } + @Override public PyObject __call__(PyObject arg0, PyObject arg1, PyObject arg2, diff --git a/src/org/python/core/PyByteArray.java b/src/org/python/core/PyByteArray.java index 88f9cc591..6597a325d 100644 --- a/src/org/python/core/PyByteArray.java +++ b/src/org/python/core/PyByteArray.java @@ -190,8 +190,8 @@ public PyByteArray(byte[] storage, int size) { * an exception about that. * * @param arg primary argument from which value is taken (may be null) - * @throws PyException (TypeError) for non-iterable, - * @throws PyException (ValueError) if iterables do not yield byte [0..255] values. + * @throws PyException {@code TypeError} for non-iterable, + * @throws PyException {@code ValueError} if iterables do not yield byte [0..255] values. */ public PyByteArray(PyObject arg) throws PyException { super(TYPE); @@ -239,7 +239,7 @@ public synchronized PyBuffer getBuffer(int flags) { /** * Try to re-use an existing exported buffer, or return null if we can't. * - * @throws PyException (BufferError) if the the flags are incompatible with the buffer + * @throws PyException {@code BufferError} if the the flags are incompatible with the buffer */ private BaseBuffer getExistingBuffer(int flags) throws PyException { BaseBuffer pybuf = null; @@ -264,7 +264,7 @@ private BaseBuffer getExistingBuffer(int flags) throws PyException { * called by the implementation of any append or insert that changes the number of bytes in the * array. * - * @throws PyException (BufferError) if there are buffer exports preventing a resize + * @throws PyException {@code BufferError} if there are buffer exports preventing a resize */ protected void resizeCheck() throws PyException { if (export != null) { @@ -341,9 +341,9 @@ protected synchronized PyByteArray getslice(int start, int stop) { */ @Override protected synchronized PyByteArray repeat(int count) { - PyByteArray ret = new PyByteArray(); - ret.setStorage(repeatImpl(count)); - return ret; + Builder builder = new Builder(size * (long) count); + builder.repeat(this, count); + return getResult(builder); } /** @@ -390,8 +390,8 @@ protected synchronized void irepeat(int count) { * * @param index index of the element to set. * @param value the value to set this element to. - * @throws PyException (AttributeError) if value cannot be converted to an integer - * @throws PyException (ValueError) if value<0 or value>255 + * @throws PyException {@code AttributeError} if value cannot be converted to an integer + * @throws PyException {@code ValueError} if value<0 or value>255 */ @Override public synchronized void pyset(int index, PyObject value) throws PyException { @@ -404,9 +404,9 @@ public synchronized void pyset(int index, PyObject value) throws PyException { * * @param index to insert at * @param element to insert (by value) - * @throws PyException (IndexError) if the index is outside the array bounds - * @throws PyException (ValueError) if element<0 or element>255 - * @throws PyException (TypeError) if the subclass is immutable + * @throws PyException {@code IndexError} if the index is outside the array bounds + * @throws PyException {@code ValueError} if element<0 or element>255 + * @throws PyException {@code TypeError} if the subclass is immutable */ @Override public synchronized void pyinsert(int index, PyObject element) { @@ -482,12 +482,8 @@ protected synchronized void setslice(int start, int stop, int step, PyObject val */ setslice(start, stop, step, (BaseBytes)value); - } else if (value instanceof BufferProtocol) { - /* - * Value supports Jython implementation of PEP 3118, and can be can be inserted without - * making a copy. - */ - setslice(start, stop, step, (BufferProtocol)value); + } else if (setsliceFromBuffer(start, stop, step, value)) { + // Value supports Jython buffer API. (We're done.) } else { /* @@ -507,7 +503,7 @@ protected synchronized void setslice(int start, int stop, int step, PyObject val * @param stop one more than the position of the last element. * @param step the step size. * @param len number of zeros to insert consistent with the slice assignment - * @throws PyException (SliceSizeError) if the value size is inconsistent with an extended slice + * @throws PyException {@code SliceSizeError} if the value size is inconsistent with an extended slice */ private void setslice(int start, int stop, int step, int len) throws PyException { if (step == 1) { @@ -536,8 +532,8 @@ private void setslice(int start, int stop, int step, int len) throws PyException * @param stop one more than the position of the last element. * @param step the step size. * @param value a PyString object consistent with the slice assignment - * @throws PyException (SliceSizeError) if the value size is inconsistent with an extended slice - * @throws PyException (ValueError) if the value is a PyUnicode + * @throws PyException {@code SliceSizeError} if the value size is inconsistent with an extended slice + * @throws PyException {@code ValueError} if the value is a PyUnicode */ private void setslice(int start, int stop, int step, PyString value) throws PyException { if (value instanceof PyUnicode) { @@ -571,11 +567,11 @@ private void setslice(int start, int stop, int step, PyString value) throws PyEx * @param stop one more than the position of the last element. * @param step the step size. * @param value an object supporting the buffer API consistent with the slice assignment - * @throws PyException (SliceSizeError) if the value size is inconsistent with an extended slice + * @throws PyException {@code SliceSizeError} if the value size is inconsistent with an extended slice */ - private void setslice(int start, int stop, int step, BufferProtocol value) throws PyException { + private void setslice(int start, int stop, int step, BufferProtocol value) throws PyException, ClassCastException { - try (PyBuffer view = value.getBuffer(PyBUF.FULL_RO)) { + try (PyBuffer view = value.getBuffer(PyBUF.SIMPLE)) { int len = view.getLen(); @@ -598,6 +594,29 @@ private void setslice(int start, int stop, int step, BufferProtocol value) throw } } + /** + * Sets the given range of elements according to Python slice assignment semantics from an + * object that might support the Jython Buffer API. + * + * @param start the position of the first element. + * @param stop one more than the position of the last element. + * @param step the step size. + * @param value an object possibly bearing the Buffer API + * @return true if the slice was set successfully, false otherwise + * @throws PyException {@code SliceSizeError} if the value size is inconsistent with an extended slice + */ + private boolean setsliceFromBuffer(int start, int stop, int step, PyObject value) + throws PyException { + if (value instanceof BufferProtocol) { + try { + setslice(start, stop, step, (BufferProtocol) value); + return true; + } catch (ClassCastException e) { /* fall through to false */ } + } + return false; + } + + /** * Sets the given range of elements according to Python slice assignment semantics from a * bytearray (or bytes). @@ -607,7 +626,7 @@ private void setslice(int start, int stop, int step, BufferProtocol value) throw * @param stop one more than the position of the last element. * @param step the step size. * @param value a bytearray (or bytes) object consistent with the slice assignment - * @throws PyException (SliceSizeError) if the value size is inconsistent with an extended slice + * @throws PyException {@code SliceSizeError} if the value size is inconsistent with an extended slice */ private void setslice(int start, int stop, int step, BaseBytes value) throws PyException { @@ -646,8 +665,8 @@ private void setslice(int start, int stop, int step, BaseBytes value) throws PyE * @param stop one more than the position of the last element. * @param step the step size. * @param iter iterable source of values to enter in the array - * @throws PyException (SliceSizeError) if the iterable size is inconsistent with an extended - * slice + * @throws PyException {@code SliceSizeError} if the iterable size is inconsistent with an + * extended slice */ private void setslice(int start, int stop, int step, Iterable iter) { /* @@ -769,8 +788,8 @@ public static PyException SliceSizeError(String valueType, int valueSize, int sl * * @param args argument array according to Jython conventions * @param kwds Keywords according to Jython conventions - * @throws PyException (TypeError) for non-iterable, - * @throws PyException (ValueError) if iterables do not yield byte [0..255] values. + * @throws PyException {@code TypeError} for non-iterable, + * @throws PyException {@code ValueError} if iterables do not yield byte [0..255] values. */ @ExposedNew @ExposedMethod(doc = BuiltinDocs.bytearray___init___doc) @@ -812,21 +831,11 @@ final synchronized void bytearray___init__(PyObject[] args, String[] kwds) { * Support for Builder * ============================================================================================ * - * Extend BaseBytes.Builder so that it can return a PyByteArray and give the superclass a hook - * for it. */ @Override - protected Builder getBuilder(int capacity) { - // Return a Builder specialised for my class - return new Builder(capacity) { - - @Override - PyByteArray getResult() { - // Create a PyByteArray from the storage that the builder holds - return new PyByteArray(getStorage(), getSize()); - } - }; + protected PyByteArray getResult(Builder b) { + return new PyByteArray(b.getStorage(), b.getSize()); } /* @@ -908,32 +917,13 @@ public PyObject __add__(PyObject o) { @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.bytearray___add___doc) final synchronized PyObject bytearray___add__(PyObject o) { - PyByteArray sum = null; - - // XXX re-write using buffer API - - if (o instanceof BaseBytes) { - BaseBytes ob = (BaseBytes)o; - // Quick route: allocate the right size bytearray and copy the two parts in. - sum = new PyByteArray(size + ob.size); - System.arraycopy(storage, offset, sum.storage, sum.offset, size); - System.arraycopy(ob.storage, ob.offset, sum.storage, sum.offset + size, ob.size); - - } else if (o.getType() == PyString.TYPE) { - // Support bytes type, which in in Python 2.7 is an alias of str. Remove in 3.0 - PyString os = (PyString)o; - // Allocate the right size bytearray and copy the two parts in. - sum = new PyByteArray(size + os.__len__()); - System.arraycopy(storage, offset, sum.storage, sum.offset, size); - sum.setslice(size, sum.size, 1, os); - - } else { - // Unsuitable type - // XXX note reversed order relative to __iadd__ may be wrong, matches Python 2.7 - throw ConcatenationTypeError(TYPE, o.getType()); - } + // Duplicate this buffer, but size it large enough to hold the sum + byte[] copy = new byte[size + o.__len__()]; + System.arraycopy(storage, offset, copy, 0, size); + PyByteArray sum = new PyByteArray(copy, size); - return sum; + // Concatenate the other buffer + return sum.bytearray___iadd__(o); } /** @@ -1017,7 +1007,7 @@ public void append(byte element) { * length 1. * * @param element the item to append. - * @throws PyException (ValueError) if element<0 or element>255 + * @throws PyException {@code ValueError} if element<0 or element>255 */ public void append(PyObject element) { bytearray_append(element); @@ -1289,7 +1279,8 @@ final int bytearray_find(PyObject sub, PyObject start, PyObject end) { * * * @param hex specification of the bytes - * @throws PyException (ValueError) if non-hex characters, or isolated ones, are encountered + * @throws PyException {@code ValueError} if non-hex characters, or isolated ones, are + * encountered */ static PyByteArray fromhex(String hex) throws PyException { return bytearray_fromhex(TYPE, hex); @@ -1325,6 +1316,9 @@ final synchronized PyObject bytearray___iadd__(PyObject o) { } else if (oType == PyString.TYPE) { // Will fail if somehow not 8-bit clean setslice(size, size, 1, (PyString)o); + } else if (setsliceFromBuffer(size, size, 1, o)) { + // No-op setsliceFromBuffer has already done the work and if it returns true then were done. + // setsliceFromBuffer will return false for PyUnicode where the buffer cannot be obtained. } else { // Unsuitable type throw ConcatenationTypeError(oType, TYPE); @@ -1359,7 +1353,7 @@ public int index(PyObject sub, PyObject start) { /** * This type is not hashable. * - * @throws PyException (TypeError) as this type is not hashable. + * @throws PyException {@code TypeError} as this type is not hashable. */ @Override public int hashCode() throws PyException { @@ -1996,12 +1990,17 @@ final synchronized void bytearray___setitem__(PyObject index, PyObject value) { */ @Override public String toString() { - return bytearray_repr(); + return this.asString(); + } + + @Override + public PyString __repr__(){ + return bytearray___repr__(); } @ExposedMethod(names = {"__repr__"}, doc = BuiltinDocs.bytearray___repr___doc) - final synchronized String bytearray_repr() { - return basebytes_repr("bytearray(b", ")"); + final synchronized PyString bytearray___repr__() { + return new PyString(basebytes_repr("bytearray(b", ")")); } /** diff --git a/src/org/python/core/PyByteArrayDerived.java b/src/org/python/core/PyByteArrayDerived.java index b5b76b1e6..214ec6c3c 100644 --- a/src/org/python/core/PyByteArrayDerived.java +++ b/src/org/python/core/PyByteArrayDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyBytecode.java b/src/org/python/core/PyBytecode.java index bfd5c2b71..b3881a65f 100644 --- a/src/org/python/core/PyBytecode.java +++ b/src/org/python/core/PyBytecode.java @@ -3,14 +3,17 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import static org.python.core.Opcode.*; public class PyBytecode extends PyBaseCode implements Traverseproc { // for debugging + public static boolean defaultDebug = false; + private static boolean debug; + private static PyObject dis, opname; + private int count = 0; // total number of opcodes run so far in this code obj private int maxCount = -1; // if -1, no cap on number of opcodes than can be run - public static boolean defaultDebug = false; - private static PyObject dis; private static synchronized PyObject get_dis() { if (dis == null) { @@ -18,7 +21,6 @@ private static synchronized PyObject get_dis() { } return dis; } - private static PyObject opname; private static synchronized PyObject get_opname() { if (opname == null) { @@ -26,7 +28,6 @@ private static synchronized PyObject get_opname() { } return opname; } - private boolean debug; public static void _allDebug(boolean setting) { defaultDebug = setting; @@ -37,8 +38,8 @@ public PyObject _debug(int maxCount) { this.maxCount = maxCount; return Py.None; } - // end debugging + public final static int CO_MAXBLOCKS = 20; // same as in CPython public final byte[] co_code; // widened to char to avoid signed byte issues public final PyObject[] co_consts; @@ -57,7 +58,6 @@ public PyBytecode(int argcount, int nlocals, int stacksize, int flags, null, null); } - // XXX - intern names HERE instead of in marshal public PyBytecode(int argcount, int nlocals, int stacksize, int flags, String codestring, PyObject[] constants, String[] names, String varnames[], @@ -90,6 +90,7 @@ public PyBytecode(int argcount, int nlocals, int stacksize, int flags, co_code = getBytes(codestring); co_lnotab = getBytes(lnotab); } + private static final String[] __members__ = { "co_name", "co_argcount", "co_varnames", "co_filename", "co_firstlineno", @@ -115,11 +116,13 @@ private void throwReadonly(String name) { throw Py.AttributeError(name); } + @Override public void __setattr__(String name, PyObject value) { // no writable attributes throwReadonly(name); } + @Override public void __delattr__(String name) { throwReadonly(name); } @@ -136,6 +139,7 @@ private static PyTuple toPyStringTuple(String[] ar) { return new PyTuple(pystr); } + @Override public PyObject __findattr_ex__(String name) { // have to craft co_varnames specially if (name == "co_varnames") { @@ -148,7 +152,7 @@ public PyObject __findattr_ex__(String name) { return toPyStringTuple(co_freevars); } if (name == "co_filename") { - return new PyString(co_filename); + return Py.fileSystemEncode(co_filename); // bytes object expected by clients } if (name == "co_name") { return new PyString(co_name); @@ -169,7 +173,6 @@ public PyObject __findattr_ex__(String name) { } enum Why { - NOT, /* No error */ EXCEPTION, /* Exception occurred */ RERAISE, /* Exception re-raised by 'finally' */ @@ -183,7 +186,6 @@ enum Why { // to enable why's to be stored on a PyStack @Untraversable private static class PyStackWhy extends PyObject { - Why why; PyStackWhy(Why why) { @@ -197,7 +199,6 @@ public String toString() { } private static class PyStackException extends PyObject implements Traverseproc { - PyException exception; PyStackException(PyException exception) { @@ -227,10 +228,9 @@ private static String stringify_blocks(PyFrame f) { return "[]"; } StringBuilder buf = new StringBuilder("["); - int len = f.f_lineno; - for (int i = 0; i < len; i++) { + for (int i = 0; i < f.f_exits.length; i++) { buf.append(f.f_exits[i].toString()); - if (i < len - 1) { + if (i < f.f_exits.length - 1) { buf.append(", "); } } @@ -241,9 +241,9 @@ private static String stringify_blocks(PyFrame f) { private void print_debug(int count, int next_instr, int line, int opcode, int oparg, PyStack stack, PyFrame f) { if (debug) { System.err.println(co_name + " " + line + ":" + - count + "," + f.f_lasti + "> " + + count + "," + f.f_lasti + "> " + opcode+" "+ get_opname().__getitem__(Py.newInteger(opcode)) + - (opcode >= Opcode.HAVE_ARGUMENT ? " " + oparg : "") + + (opcode >= HAVE_ARGUMENT ? " " + oparg : "") + ", stack: " + stack.toString() + ", blocks: " + stringify_blocks(f)); } @@ -287,7 +287,6 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { // XXX - optimization opportunities // 1. consider detaching the setting/getting of frame fields to improve performance, instead do this // in a shadow version of the frame that we copy back to on entry/exit and downcalls - if (debug) { System.err.println(co_name + ":" + f.f_lasti + "/" + co_code.length + ", cells:" + Arrays.toString(co_cellvars) + ", free:" + Arrays.toString(co_freevars)); @@ -345,7 +344,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { } opcode = getUnsigned(co_code, next_instr); - if (opcode >= Opcode.HAVE_ARGUMENT) { + if (opcode >= HAVE_ARGUMENT) { next_instr += 2; oparg = (getUnsigned(co_code, next_instr) << 8) + getUnsigned(co_code, next_instr - 1); } @@ -356,42 +355,42 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { f.f_lasti = next_instr; switch (opcode) { - case Opcode.NOP: + case NOP: break; - case Opcode.LOAD_FAST: + case LOAD_FAST: stack.push(f.getlocal(oparg)); break; - case Opcode.LOAD_CONST: + case LOAD_CONST: stack.push(co_consts[oparg]); break; - case Opcode.STORE_FAST: + case STORE_FAST: f.setlocal(oparg, stack.pop()); break; - case Opcode.POP_TOP: + case POP_TOP: stack.pop(); break; - case Opcode.ROT_TWO: + case ROT_TWO: stack.rot2(); break; - case Opcode.ROT_THREE: + case ROT_THREE: stack.rot3(); break; - case Opcode.ROT_FOUR: + case ROT_FOUR: stack.rot4(); break; - case Opcode.DUP_TOP: + case DUP_TOP: stack.dup(); break; - case Opcode.DUP_TOPX: { + case DUP_TOPX: { if (oparg == 2 || oparg == 3) { stack.dup(oparg); } else { @@ -401,41 +400,41 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.UNARY_POSITIVE: + case UNARY_POSITIVE: stack.push(stack.pop().__pos__()); break; - case Opcode.UNARY_NEGATIVE: + case UNARY_NEGATIVE: stack.push(stack.pop().__neg__()); break; - case Opcode.UNARY_NOT: + case UNARY_NOT: stack.push(stack.pop().__not__()); break; - case Opcode.UNARY_CONVERT: + case UNARY_CONVERT: stack.push(stack.pop().__repr__()); break; - case Opcode.UNARY_INVERT: + case UNARY_INVERT: stack.push(stack.pop().__invert__()); break; - case Opcode.BINARY_POWER: { + case BINARY_POWER: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._pow(b)); break; } - case Opcode.BINARY_MULTIPLY: { + case BINARY_MULTIPLY: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._mul(b)); break; } - case Opcode.BINARY_DIVIDE: { + case BINARY_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); @@ -447,63 +446,63 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.BINARY_TRUE_DIVIDE: { + case BINARY_TRUE_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._truediv(b)); break; } - case Opcode.BINARY_FLOOR_DIVIDE: { + case BINARY_FLOOR_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._floordiv(b)); break; } - case Opcode.BINARY_MODULO: { + case BINARY_MODULO: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._mod(b)); break; } - case Opcode.BINARY_ADD: { + case BINARY_ADD: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._add(b)); break; } - case Opcode.BINARY_SUBTRACT: { + case BINARY_SUBTRACT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._sub(b)); break; } - case Opcode.BINARY_SUBSCR: { + case BINARY_SUBSCR: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a.__getitem__(b)); break; } - case Opcode.BINARY_LSHIFT: { + case BINARY_LSHIFT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._lshift(b)); break; } - case Opcode.BINARY_RSHIFT: { + case BINARY_RSHIFT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._rshift(b)); break; } - case Opcode.BINARY_AND: { + case BINARY_AND: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._and(b)); @@ -511,42 +510,49 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { } - case Opcode.BINARY_XOR: { + case BINARY_XOR: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._xor(b)); break; } - case Opcode.BINARY_OR: { + case BINARY_OR: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._or(b)); break; } - case Opcode.LIST_APPEND: { + case LIST_APPEND: { PyObject b = stack.pop(); - PyList a = (PyList) (stack.pop()); + PyList a = (PyList) stack.top(oparg); a.append(b); break; } - case Opcode.INPLACE_POWER: { + case SET_ADD: { + PyObject b = stack.pop(); + PySet a = (PySet) stack.top(oparg); + a.add(b); + break; + } + + case INPLACE_POWER: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._ipow(b)); break; } - case Opcode.INPLACE_MULTIPLY: { + case INPLACE_MULTIPLY: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._imul(b)); break; } - case Opcode.INPLACE_DIVIDE: { + case INPLACE_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); if (!co_flags.isFlagSet(CodeFlag.CO_FUTURE_DIVISION)) { @@ -557,111 +563,111 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.INPLACE_TRUE_DIVIDE: { + case INPLACE_TRUE_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._itruediv(b)); break; } - case Opcode.INPLACE_FLOOR_DIVIDE: { + case INPLACE_FLOOR_DIVIDE: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._ifloordiv(b)); break; } - case Opcode.INPLACE_MODULO: { + case INPLACE_MODULO: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._imod(b)); break; } - case Opcode.INPLACE_ADD: { + case INPLACE_ADD: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._iadd(b)); break; } - case Opcode.INPLACE_SUBTRACT: { + case INPLACE_SUBTRACT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._isub(b)); break; } - case Opcode.INPLACE_LSHIFT: { + case INPLACE_LSHIFT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._ilshift(b)); break; } - case Opcode.INPLACE_RSHIFT: { + case INPLACE_RSHIFT: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._irshift(b)); break; } - case Opcode.INPLACE_AND: { + case INPLACE_AND: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._iand(b)); break; } - case Opcode.INPLACE_XOR: { + case INPLACE_XOR: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._ixor(b)); break; } - case Opcode.INPLACE_OR: { + case INPLACE_OR: { PyObject b = stack.pop(); PyObject a = stack.pop(); stack.push(a._ior(b)); break; } - case Opcode.SLICE + 0: - case Opcode.SLICE + 1: - case Opcode.SLICE + 2: - case Opcode.SLICE + 3: { - PyObject stop = (((opcode - Opcode.SLICE) & 2) != 0) ? stack.pop() : null; - PyObject start = (((opcode - Opcode.SLICE) & 1) != 0) ? stack.pop() : null; + case SLICE: + case SLICE_1: + case SLICE_2: + case SLICE_3: { + PyObject stop = (((opcode - SLICE) & 2) != 0) ? stack.pop() : null; + PyObject start = (((opcode - SLICE) & 1) != 0) ? stack.pop() : null; PyObject obj = stack.pop(); stack.push(obj.__getslice__(start, stop)); break; } - case Opcode.STORE_SLICE + 0: - case Opcode.STORE_SLICE + 1: - case Opcode.STORE_SLICE + 2: - case Opcode.STORE_SLICE + 3: { - PyObject stop = (((opcode - Opcode.STORE_SLICE) & 2) != 0) ? stack.pop() : null; - PyObject start = (((opcode - Opcode.STORE_SLICE) & 1) != 0) ? stack.pop() : null; + case STORE_SLICE: + case STORE_SLICE_1: + case STORE_SLICE_2: + case STORE_SLICE_3: { + PyObject stop = (((opcode - STORE_SLICE) & 2) != 0) ? stack.pop() : null; + PyObject start = (((opcode - STORE_SLICE) & 1) != 0) ? stack.pop() : null; PyObject obj = stack.pop(); PyObject value = stack.pop(); obj.__setslice__(start, stop, value); break; } - case Opcode.DELETE_SLICE + 0: - case Opcode.DELETE_SLICE + 1: - case Opcode.DELETE_SLICE + 2: - case Opcode.DELETE_SLICE + 3: { - PyObject stop = (((opcode - Opcode.DELETE_SLICE) & 2) != 0) ? stack.pop() : null; - PyObject start = (((opcode - Opcode.DELETE_SLICE) & 1) != 0) ? stack.pop() : null; + case DELETE_SLICE: + case DELETE_SLICE_1: + case DELETE_SLICE_2: + case DELETE_SLICE_3: { + PyObject stop = (((opcode - DELETE_SLICE) & 2) != 0) ? stack.pop() : null; + PyObject start = (((opcode - DELETE_SLICE) & 1) != 0) ? stack.pop() : null; PyObject obj = stack.pop(); obj.__delslice__(start, stop); break; } - case Opcode.STORE_SUBSCR: { + case STORE_SUBSCR: { PyObject key = stack.pop(); PyObject obj = stack.pop(); PyObject value = stack.pop(); @@ -669,34 +675,34 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.DELETE_SUBSCR: { + case DELETE_SUBSCR: { PyObject key = stack.pop(); PyObject obj = stack.pop(); obj.__delitem__(key); break; } - case Opcode.PRINT_EXPR: + case PRINT_EXPR: PySystemState.displayhook(stack.pop()); break; - case Opcode.PRINT_ITEM_TO: + case PRINT_ITEM_TO: Py.printComma(stack.pop(), stack.pop()); break; - case Opcode.PRINT_ITEM: + case PRINT_ITEM: Py.printComma(stack.pop()); break; - case Opcode.PRINT_NEWLINE_TO: + case PRINT_NEWLINE_TO: Py.printlnv(stack.pop()); break; - case Opcode.PRINT_NEWLINE: + case PRINT_NEWLINE: Py.println(); break; - case Opcode.RAISE_VARARGS: + case RAISE_VARARGS: switch (oparg) { case 3: { @@ -720,29 +726,31 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { throw Py.SystemError("bad RAISE_VARARGS oparg"); } - case Opcode.LOAD_LOCALS: + case LOAD_LOCALS: stack.push(f.f_locals); break; - case Opcode.RETURN_VALUE: + case RETURN_VALUE: retval = stack.pop(); why = Why.RETURN; break; - case Opcode.YIELD_VALUE: + case YIELD_VALUE: retval = stack.pop(); + // Note: CPython calls f->f_stacktop = stack_pointer; here why = Why.YIELD; break; - case Opcode.EXEC_STMT: { + case EXEC_STMT: { PyObject locals = stack.pop(); PyObject globals = stack.pop(); PyObject code = stack.pop(); + //Todo: Better make it possible to use PyFrame f here: Py.exec(code, globals == Py.None ? null : globals, locals == Py.None ? null : locals); break; } - case Opcode.POP_BLOCK: { + case POP_BLOCK: { PyTryBlock b = popBlock(f); while (stack.size() > b.b_level) { stack.pop(); @@ -750,7 +758,8 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.END_FINALLY: { + case END_FINALLY: { + // Todo: Review this regarding Python 2.7-update PyObject v = stack.pop(); if (v instanceof PyStackWhy) { why = ((PyStackWhy) v).why; @@ -759,10 +768,16 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { retval = stack.pop(); } } else if (v instanceof PyStackException) { + stack.top -= 2; // to pop value, traceback ts.exception = ((PyStackException) v).exception; why = Why.RERAISE; - } else if (v instanceof PyString) { + // This shouldn't happen, because Jython always pushes + // exception type as PyException-object. + // Todo: Test, if it can be removed. + PyObject value = stack.pop(); + PyObject traceback = stack.pop(); + ts.exception = new PyException(v, value, (PyTraceback) traceback); why = Why.RERAISE; } else if (v != Py.None) { throw Py.SystemError("'finally' pops bad exception"); @@ -770,7 +785,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.BUILD_CLASS: { + case BUILD_CLASS: { PyObject methods = stack.pop(); PyObject bases[] = ((PySequenceList) (stack.pop())).getArray(); String name = stack.pop().toString(); @@ -778,50 +793,51 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.STORE_NAME: + case STORE_NAME: f.setlocal(co_names[oparg], stack.pop()); break; - case Opcode.DELETE_NAME: + case DELETE_NAME: f.dellocal(co_names[oparg]); break; - case Opcode.UNPACK_SEQUENCE: + case UNPACK_SEQUENCE: unpack_iterable(oparg, stack); break; - case Opcode.STORE_ATTR: { + case STORE_ATTR: { PyObject obj = stack.pop(); PyObject v = stack.pop(); obj.__setattr__(co_names[oparg], v); break; } - case Opcode.DELETE_ATTR: + case DELETE_ATTR: stack.pop().__delattr__(co_names[oparg]); break; - case Opcode.STORE_GLOBAL: + case STORE_GLOBAL: f.setglobal(co_names[oparg], stack.pop()); break; - case Opcode.DELETE_GLOBAL: + case DELETE_GLOBAL: f.delglobal(co_names[oparg]); break; - case Opcode.LOAD_NAME: + case LOAD_NAME: stack.push(f.getname(co_names[oparg])); break; - case Opcode.LOAD_GLOBAL: + case LOAD_GLOBAL: stack.push(f.getglobal(co_names[oparg])); break; - case Opcode.DELETE_FAST: + case DELETE_FAST: f.dellocal(oparg); break; - case Opcode.LOAD_CLOSURE: { + case LOAD_CLOSURE: { + // Todo: Review this regarding Python 2.7-update PyCell cell = (PyCell) (f.getclosure(oparg)); if (cell.ob_ref == null) { String name; @@ -854,7 +870,8 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.LOAD_DEREF: { + case LOAD_DEREF: { + // Todo: Review this regarding Python 2.7-update // common code from LOAD_CLOSURE PyCell cell = (PyCell) (f.getclosure(oparg)); if (cell.ob_ref == null) { @@ -888,65 +905,85 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.STORE_DEREF: + case STORE_DEREF: f.setderef(oparg, stack.pop()); break; - case Opcode.BUILD_TUPLE: + case BUILD_TUPLE: stack.push(new PyTuple(stack.popN(oparg))); break; - case Opcode.BUILD_LIST: + case BUILD_LIST: stack.push(new PyList(stack.popN(oparg))); break; - case Opcode.BUILD_MAP: - stack.push(new PyDictionary()); + case BUILD_SET: + stack.push(new PySet(stack.popN(oparg))); + break; + + case BUILD_MAP: + // oparg contains initial capacity: + stack.push(new PyDictionary(PyDictionary.TYPE, oparg)); break; - case Opcode.LOAD_ATTR: { + case STORE_MAP: { + PyObject key = stack.pop(); + PyObject val = stack.pop(); + stack.top().__setitem__(key, val); + break; + } + + case MAP_ADD: { + PyObject key = stack.pop(); + PyObject val = stack.pop(); + stack.top(oparg).__setitem__(key, val); + break; + } + + case LOAD_ATTR: { String name = co_names[oparg]; stack.push(stack.pop().__getattr__(name)); break; } - case Opcode.COMPARE_OP: { + case COMPARE_OP: { PyObject b = stack.pop(); PyObject a = stack.pop(); switch (oparg) { - case Opcode.PyCmp_LT: + case PyCmp_LT: stack.push(a._lt(b)); break; - case Opcode.PyCmp_LE: + case PyCmp_LE: stack.push(a._le(b)); break; - case Opcode.PyCmp_EQ: + case PyCmp_EQ: stack.push(a._eq(b)); break; - case Opcode.PyCmp_NE: + case PyCmp_NE: stack.push(a._ne(b)); break; - case Opcode.PyCmp_GT: + case PyCmp_GT: stack.push(a._gt(b)); break; - case Opcode.PyCmp_GE: + case PyCmp_GE: stack.push(a._ge(b)); break; - case Opcode.PyCmp_IN: + case PyCmp_IN: stack.push(a._in(b)); break; - case Opcode.PyCmp_NOT_IN: + case PyCmp_NOT_IN: stack.push(a._notin(b)); break; - case Opcode.PyCmp_IS: + case PyCmp_IS: stack.push(a._is(b)); break; - case Opcode.PyCmp_IS_NOT: + case PyCmp_IS_NOT: stack.push(a._isnot(b)); break; - case Opcode.PyCmp_EXC_MATCH: + case PyCmp_EXC_MATCH: + // Todo: Review this regarding Python 2.7-update if (a instanceof PyStackException) { PyException pye = ((PyStackException) a).exception; stack.push(Py.newBoolean(pye.match(b))); @@ -959,7 +996,8 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.IMPORT_NAME: { + case IMPORT_NAME: { + // Todo: Review this regarding Python 2.7-update PyObject __import__ = f.f_builtins.__finditem__("__import__"); if (__import__ == null) { throw Py.ImportError("__import__ not found"); @@ -976,13 +1014,14 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.IMPORT_STAR: { + case IMPORT_STAR: { + // Todo: Review this regarding Python 2.7-update PyObject module = stack.pop(); imp.importAll(module, f); break; } - case Opcode.IMPORT_FROM: + case IMPORT_FROM: String name = co_names[oparg]; try { stack.push(stack.top().__getattr__(name)); @@ -996,27 +1035,43 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { } break; - case Opcode.JUMP_FORWARD: + case JUMP_FORWARD: next_instr += oparg; break; - case Opcode.JUMP_IF_FALSE: - if (!stack.top().__nonzero__()) { - next_instr += oparg; + case POP_JUMP_IF_FALSE: + if (!stack.pop().__nonzero__()) { + next_instr = oparg; + } + break; + + case POP_JUMP_IF_TRUE: + if (stack.pop().__nonzero__()) { + next_instr = oparg; } break; - case Opcode.JUMP_IF_TRUE: + case JUMP_IF_FALSE_OR_POP: if (stack.top().__nonzero__()) { - next_instr += oparg; + --stack.top; + } else { + next_instr = oparg; } break; - case Opcode.JUMP_ABSOLUTE: + case JUMP_IF_TRUE_OR_POP: + if (!stack.top().__nonzero__()) { + --stack.top; + } else { + next_instr = oparg; + } + break; + + case JUMP_ABSOLUTE: next_instr = oparg; break; - case Opcode.GET_ITER: { + case GET_ITER: { PyObject it = stack.top().__iter__(); if (it != null) { stack.set_top(it); @@ -1024,7 +1079,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.FOR_ITER: { + case FOR_ITER: { PyObject it = stack.pop(); try { PyObject x = it.__iternext__(); @@ -1042,52 +1097,95 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.BREAK_LOOP: + case BREAK_LOOP: why = Why.BREAK; break; - case Opcode.CONTINUE_LOOP: + case CONTINUE_LOOP: retval = Py.newInteger(oparg); if (retval.__nonzero__()) { why = Why.CONTINUE; } break; - case Opcode.SETUP_LOOP: - case Opcode.SETUP_EXCEPT: - case Opcode.SETUP_FINALLY: + case SETUP_LOOP: + case SETUP_EXCEPT: + case SETUP_FINALLY: pushBlock(f, new PyTryBlock(opcode, next_instr + oparg, stack.size())); break; - case Opcode.WITH_CLEANUP: { - /* - TOP is the context.__exit__ bound method. - Below that are 1-3 values indicating how/why - we entered the finally clause: - - SECOND = None - - (SECOND, THIRD) = (WHY_{RETURN,CONTINUE}), retval - - SECOND = WHY_*; no retval below it - - (SECOND, THIRD, FOURTH) = exc_info() + case SETUP_WITH: { + PyObject w = stack.top(); + PyObject exit = w.__getattr__("__exit__"); + if (exit == null) { + break; + } + stack.set_top(exit); + PyObject enter = w.__getattr__("__enter__"); + if (enter == null) { + break; + } + w = enter.__call__(); + if (w == null) { + break; + } + /* Setup a finally block (SETUP_WITH as a block is + equivalent to SETUP_FINALLY except it normalizes + the exception) before pushing the result of + __enter__ on the stack. */ + pushBlock(f, new PyTryBlock(opcode, next_instr + oparg, stack.size())); + stack.push(w); + break; + } + + case WITH_CLEANUP: { + /* At the top of the stack are 1-3 values indicating + how/why we entered the finally clause: + - TOP = None + - (TOP, SECOND) = (WHY_{RETURN,CONTINUE}), retval + - TOP = WHY_*; no retval below it + - (TOP, SECOND, THIRD) = exc_info() + Below them is EXIT, the context.__exit__ bound method. In the last case, we must call - TOP(SECOND, THIRD, FOURTH) + EXIT(TOP, SECOND, THIRD) otherwise we must call - TOP(None, None, None) + EXIT(None, None, None) + + In all cases, we remove EXIT from the stack, leaving + the rest in the same order. In addition, if the stack represents an exception, - *and* the function call returns a 'true' value, we + *and* the function call returns a 'true' value, we "zap" this information, to prevent END_FINALLY from re-raising the exception. (But non-local gotos should still be resumed.) - */ - PyObject exit = stack.top(); - PyObject u = stack.top(2); - PyObject v; - PyObject w; - if (u == Py.None || u instanceof PyStackWhy) { + */ + PyObject exit; + PyObject u = stack.pop(), v, w; + if (u == Py.None) { + exit = stack.top(); + stack.set_top(u); + v = w = Py.None; + } else if (u instanceof PyStackWhy) { + switch (((PyStackWhy) u).why) { + case RETURN: + case CONTINUE: + exit = stack.top(2); + stack.set_top(2, stack.top()); + stack.set_top(u); + break; + default: + exit = stack.top(); + stack.set_top(u); + } u = v = w = Py.None; } else { - v = stack.top(3); - w = stack.top(4); + v = stack.top(); + w = stack.top(2); + exit = stack.top(3); + stack.set_top(u); + stack.set_top(2, v); + stack.set_top(3, w); } PyObject x = null; if (u instanceof PyStackException) { @@ -1098,15 +1196,14 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { } if (u != Py.None && x != null && x.__nonzero__()) { - stack.popN(4); // XXX - consider stack.stackadj op - stack.push(Py.None); - } else { - stack.pop(); // this should be popping off a block + stack.top -= 2; // XXX - consider stack.stackadj op + stack.set_top(Py.None); } break; } - case Opcode.CALL_FUNCTION: { + case CALL_FUNCTION: { + // Todo: Review this regarding Python 2.7-update int na = oparg & 0xff; int nk = (oparg >> 8) & 0xff; @@ -1118,12 +1215,13 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.CALL_FUNCTION_VAR: - case Opcode.CALL_FUNCTION_KW: - case Opcode.CALL_FUNCTION_VAR_KW: { + case CALL_FUNCTION_VAR: + case CALL_FUNCTION_KW: + case CALL_FUNCTION_VAR_KW: { + // Todo: Review this regarding Python 2.7-update int na = oparg & 0xff; int nk = (oparg >> 8) & 0xff; - int flags = (opcode - Opcode.CALL_FUNCTION) & 3; + int flags = (opcode - CALL_FUNCTION) & 3; call_function(na, nk, (flags & CALL_FLAG_VAR) != 0, (flags & CALL_FLAG_KW) != 0, @@ -1131,7 +1229,8 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.MAKE_FUNCTION: { + case MAKE_FUNCTION: { + // Todo: Review this regarding Python 2.7-update PyCode code = (PyCode) stack.pop(); PyObject[] defaults = stack.popN(oparg); PyObject doc = null; @@ -1143,7 +1242,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.MAKE_CLOSURE: { + case MAKE_CLOSURE: { PyCode code = (PyCode) stack.pop(); PyObject[] closure_cells = ((PySequenceList) (stack.pop())).getArray(); PyObject[] defaults = stack.popN(oparg); @@ -1156,7 +1255,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.BUILD_SLICE: { + case BUILD_SLICE: { PyObject step = oparg == 3 ? stack.pop() : null; PyObject stop = stack.pop(); PyObject start = stack.pop(); @@ -1164,10 +1263,12 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { break; } - case Opcode.EXTENDED_ARG: + case EXTENDED_ARG: + // Todo: Review this regarding Python 2.7-update opcode = getUnsigned(co_code, next_instr++); next_instr += 2; - oparg = oparg << 16 | ((getUnsigned(co_code, next_instr) << 8) + getUnsigned(co_code, next_instr - 1)); + oparg = oparg << 16 | ((getUnsigned(co_code, next_instr) << 8) + + getUnsigned(co_code, next_instr - 1)); break; default: @@ -1203,7 +1304,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { System.err.println("Processing block: " + b); } assert (why != Why.YIELD); - if (b.b_type == Opcode.SETUP_LOOP && why == Why.CONTINUE) { + if (b.b_type == SETUP_LOOP && why == Why.CONTINUE) { pushBlock(f, b); why = Why.NOT; next_instr = retval.asInt(); @@ -1212,15 +1313,16 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { while (stack.size() > b.b_level) { stack.pop(); } - if (b.b_type == Opcode.SETUP_LOOP && why == Why.BREAK) { + if (b.b_type == SETUP_LOOP && why == Why.BREAK) { why = Why.NOT; next_instr = b.b_handler; break; } - if (b.b_type == Opcode.SETUP_FINALLY || (b.b_type == Opcode.SETUP_EXCEPT && why == Why.EXCEPTION)) { + if (b.b_type == SETUP_FINALLY || (b.b_type == SETUP_EXCEPT && why == Why.EXCEPTION) + || b.b_type == SETUP_WITH) { if (why == Why.EXCEPTION) { PyException exc = ts.exception; - if (b.b_type == Opcode.SETUP_EXCEPT) { + if (b.b_type == SETUP_EXCEPT || b.b_type == SETUP_WITH) { exc.normalize(); } stack.push(exc.traceback); @@ -1264,7 +1366,7 @@ protected PyObject interpret(PyFrame f, ThreadState ts) { ", blocks: " + stringify_blocks(f)); } - if (why == why.EXCEPTION) { + if (why == Why.EXCEPTION) { throw ts.exception; } @@ -1380,7 +1482,6 @@ private static void unpack_iterable(int oparg, PyStack stack) { } private static class PyStack { - final PyObject[] stack; int top = -1; @@ -1408,6 +1509,10 @@ void set_top(PyObject v) { stack[top] = v; } + void set_top(int n, PyObject v) { + stack[top - n + 1] = v; + } + void dup() { stack[top + 1] = stack[top]; top++; @@ -1500,15 +1605,12 @@ private String upto(String x, int n) { } @Untraversable - private static class PyTryBlock extends PyObject { // purely to sit on top of the existing PyFrame in f_exits!!! - + private static class PyTryBlock extends PyObject { + // purely to sit on top of the existing PyFrame in f_exits!!! int b_type; /* what kind of block this is */ - int b_handler; /* where to jump to find handler */ - int b_level; /* value stack level to pop to */ - PyTryBlock(int type, int handler, int level) { b_type = type; b_handler = handler; @@ -1540,26 +1642,10 @@ protected int getline(PyFrame f) { } private class LineCache { - - private class Pair { - - private final int addr; - private final int line; - - private Pair(int a, int b) { - this.addr = a; - this.line = b; - } - - public String toString() { - return "(" + addr + "," + line + ")"; - } - } List addr_breakpoints = new ArrayList(); List lines = new ArrayList(); // length should be one more than addr_breakpoints private LineCache() { // based on dis.findlinestarts - int size = co_lnotab.length / 2; int p = 0; int lastline = -1; @@ -1584,7 +1670,6 @@ private LineCache() { // based on dis.findlinestarts } private int getline(int addrq) { // bisect_right to the lineno - int lo = 0; int hi = addr_breakpoints.size(); while (lo < hi) { diff --git a/src/org/python/core/PyClass.java b/src/org/python/core/PyClass.java index 022bbddaf..289955c84 100644 --- a/src/org/python/core/PyClass.java +++ b/src/org/python/core/PyClass.java @@ -46,7 +46,7 @@ public static PyObject classobj___new__(PyObject name, PyObject bases, PyObject if (!name.getType().isSubType(PyString.TYPE)) { throw Py.TypeError("PyClass_New: name must be a string"); } - if (!(dict instanceof PyStringMap || dict instanceof PyDictionary)) { + if (!(dict instanceof AbstractDict)) { throw Py.TypeError("PyClass_New: dict must be a dictionary"); } PyType.ensureDoc(dict); @@ -248,7 +248,7 @@ public boolean isSubClass(PyClass superclass) { } public void setDict(PyObject value) { - if (value == null || !(value instanceof PyStringMap || value instanceof PyDictionary)) { + if (value == null || !(value instanceof AbstractDict)) { throw Py.TypeError("__dict__ must be a dictionary object"); } __dict__ = value; diff --git a/src/org/python/core/PyClassMethodDerived.java b/src/org/python/core/PyClassMethodDerived.java index 4173207a1..971877852 100644 --- a/src/org/python/core/PyClassMethodDerived.java +++ b/src/org/python/core/PyClassMethodDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyComplex.java b/src/org/python/core/PyComplex.java index f6bd94bbb..bc7856d63 100644 --- a/src/org/python/core/PyComplex.java +++ b/src/org/python/core/PyComplex.java @@ -924,7 +924,7 @@ final PyObject complex___format__(PyObject formatSpec) { * * @param spec a parsed PEP-3101 format specification. * @return 0, 1, or other value for none-format, a float format, or incorrect type. - * @throws PyException(ValueError) if the specification is faulty. + * @throws PyException {@code ValueError} if the specification is faulty. */ @SuppressWarnings("fallthrough") private static int checkSpecification(Spec spec) { diff --git a/src/org/python/core/PyComplexDerived.java b/src/org/python/core/PyComplexDerived.java index 51da98807..15a83fba2 100644 --- a/src/org/python/core/PyComplexDerived.java +++ b/src/org/python/core/PyComplexDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java index f0ec7a6c6..833872e87 100644 --- a/src/org/python/core/PyDictionary.java +++ b/src/org/python/core/PyDictionary.java @@ -16,6 +16,8 @@ import java.util.concurrent.ConcurrentHashMap; import org.python.core.AbstractDict.ValuesIter; +import org.python.core.AbstractDict.KeysIter; +import org.python.core.AbstractDict.ItemsIter; import org.python.expose.ExposedClassMethod; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; @@ -776,7 +778,7 @@ public PyObject iteritems() { @ExposedMethod(doc = BuiltinDocs.dict_iteritems_doc) final PyObject dict_iteritems() { - return new ItemsIter(getMap().entrySet()); + return new ItemsIter(getMap().entrySet()); } /** @@ -788,7 +790,7 @@ public PyObject iterkeys() { @ExposedMethod(doc = BuiltinDocs.dict_iterkeys_doc) final PyObject dict_iterkeys() { - return new ValuesIter(getMap().keySet()); + return new KeysIter(getMap().keySet()); } /** @@ -859,27 +861,6 @@ public PyObject viewitems() { public PyObject viewvalues() { return super.viewvalues(); } - - class ItemsIter extends PyIterator { - - private final Iterator> iterator; - - private final int size; - - public ItemsIter(Set> items) { - iterator = items.iterator(); - size = items.size(); - } - - @Override - public PyObject __iternext__() { - if (!iterator.hasNext()) { - return null; - } - Entry entry = iterator.next(); - return new PyTuple(entry.getKey(), entry.getValue()); - } - } public Set pyKeySet() { return internalMap.keySet(); @@ -1009,7 +990,7 @@ public PyObject __iter__() { @ExposedMethod(doc = BuiltinDocs.set___iter___doc) final PyObject dict_keys___iter__() { - return new ValuesIter(dvDict.pyKeySet()); + return new KeysIter(dvDict.pyKeySet()); } @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.set___ne___doc) diff --git a/src/org/python/core/PyDictionaryDerived.java b/src/org/python/core/PyDictionaryDerived.java index fb1aff324..eb1b9cf4e 100644 --- a/src/org/python/core/PyDictionaryDerived.java +++ b/src/org/python/core/PyDictionaryDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyEnumerateDerived.java b/src/org/python/core/PyEnumerateDerived.java index d882cbc52..d3a3e3a51 100644 --- a/src/org/python/core/PyEnumerateDerived.java +++ b/src/org/python/core/PyEnumerateDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyException.java b/src/org/python/core/PyException.java index f4d2d464c..69ed58edd 100644 --- a/src/org/python/core/PyException.java +++ b/src/org/python/core/PyException.java @@ -62,21 +62,37 @@ public PyException(PyObject type, String value) { } private boolean printingStackTrace = false; + @Override public void printStackTrace() { Py.printException(this); } + @Override public Throwable fillInStackTrace() { return Options.includeJavaStackInExceptions ? super.fillInStackTrace() : this; } + @Override + public String getMessage() { + normalize(); + return Py.formatException(type, value); + } + + @Override public synchronized void printStackTrace(PrintStream s) { if (printingStackTrace) { super.printStackTrace(s); } else { try { + /* + * Ensure that non-ascii characters are made printable. IOne would prefer to emit + * Unicode, but the output stream too often only accepts bytes. (s is not + * necessarily a console, e.g. during a doctest.) + */ + PyFile err = new PyFile(s); + err.setEncoding("ascii", "backslashreplace"); printingStackTrace = true; - Py.displayException(type, value, traceback, new PyFile(s)); + Py.displayException(type, value, traceback, err); } finally { printingStackTrace = false; } @@ -92,12 +108,9 @@ public synchronized void super__printStackTrace(PrintWriter w) { } } + @Override public synchronized String toString() { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - if (!printingStackTrace) { - printStackTrace(new PrintStream(buf)); - } - return buf.toString(); + return Py.exceptionToString(type, value, traceback); } /** @@ -332,10 +345,11 @@ public static boolean isExceptionInstance(PyObject obj) { public static String exceptionClassName(PyObject obj) { return obj instanceof PyClass ? ((PyClass)obj).__name__ : ((PyType)obj).fastGetName(); } - - + + /* Traverseproc support */ + @Override public int traverse(Visitproc visit, Object arg) { int retValue; if (type != null) { @@ -357,6 +371,7 @@ public int traverse(Visitproc visit, Object arg) { return 0; } + @Override public boolean refersDirectlyTo(PyObject ob) { return ob != null && (type == ob || value == ob || traceback == ob); } diff --git a/src/org/python/core/PyFile.java b/src/org/python/core/PyFile.java index 224c4f0c0..22fe63383 100644 --- a/src/org/python/core/PyFile.java +++ b/src/org/python/core/PyFile.java @@ -168,10 +168,6 @@ final void file___init__(PyObject[] args, String[] kwds) { ArgParser ap = new ArgParser("file", args, kwds, new String[] {"name", "mode", "buffering"}, 1); PyObject name = ap.getPyObject(0); - if (!(name instanceof PyString)) { - throw Py.TypeError("coercing to Unicode: need string, '" + name.getType().fastGetName() - + "' type found"); - } String mode = ap.getString(1, "r"); int bufsize = ap.getInt(2, -1); file___init__(new FileIO((PyString) name, parseMode(mode)), name, mode, bufsize); @@ -179,7 +175,7 @@ final void file___init__(PyObject[] args, String[] kwds) { } private void file___init__(RawIOBase raw, String name, String mode, int bufsize) { - file___init__(raw, new PyString(name), mode, bufsize); + file___init__(raw, Py.newStringOrUnicode(name), mode, bufsize); } private void file___init__(RawIOBase raw, PyObject name, String mode, int bufsize) { @@ -500,18 +496,20 @@ private String asWritable(PyObject obj, String message) { } else if (obj instanceof PyArray && !binary) { // Fall through to TypeError. (If binary, BufferProtocol takes care of PyArray.) - } else if (obj instanceof BufferProtocol) { - // Try to get a byte-oriented buffer - try (PyBuffer buf = ((BufferProtocol)obj).getBuffer(PyBUF.FULL_RO)) { + } else { + // Try to get a simple byte-oriented buffer + try (PyBuffer buf = ((BufferProtocol)obj).getBuffer(PyBUF.SIMPLE)) { // ... and treat those bytes as a String return buf.toString(); + } catch (ClassCastException e) { + // Does not implement BufferProtocol (in reality). Fall through to message. } } if (message == null) { // Messages differ for text or binary streams (CPython) but we always add the type - String.format("%s buffer, not %.200s", (binary ? "must be string or" - : "expected a character"), obj.getType().fastGetName()); + String fmt = "expected a string or%s buffer, not %.200s"; + message = String.format(fmt, (binary ? "" : " character"), obj.getType().fastGetName()); } throw Py.TypeError(message); } diff --git a/src/org/python/core/PyFileDerived.java b/src/org/python/core/PyFileDerived.java index 327e5e629..79c77e796 100644 --- a/src/org/python/core/PyFileDerived.java +++ b/src/org/python/core/PyFileDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyFloat.java b/src/org/python/core/PyFloat.java index 9bcb56214..6ff4f9d18 100644 --- a/src/org/python/core/PyFloat.java +++ b/src/org/python/core/PyFloat.java @@ -301,9 +301,9 @@ final boolean float___nonzero__() { public Object __tojava__(Class c) { if (c == Double.TYPE || c == Number.class || c == Double.class || c == Object.class || c == Serializable.class) { - return new Double(getValue()); + return Double.valueOf(getValue()); } else if (c == Float.TYPE || c == Float.class) { - return new Float(getValue()); + return Float.valueOf((float) getValue()); } return super.__tojava__(c); } @@ -979,7 +979,7 @@ final PyObject float___format__(PyObject formatSpec) { * * @param spec a parsed PEP-3101 format specification. * @return a formatter ready to use, or null if the type is not a floating point format type. - * @throws PyException(ValueError) if the specification is faulty. + * @throws PyException {@code ValueError} if the specification is faulty. */ @SuppressWarnings("fallthrough") static FloatFormatter prepareFormatter(Spec spec) { diff --git a/src/org/python/core/PyFloatDerived.java b/src/org/python/core/PyFloatDerived.java index 21413073d..4a551fb9f 100644 --- a/src/org/python/core/PyFloatDerived.java +++ b/src/org/python/core/PyFloatDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyFrozenSetDerived.java b/src/org/python/core/PyFrozenSetDerived.java index b3f587191..7ab5d039f 100644 --- a/src/org/python/core/PyFrozenSetDerived.java +++ b/src/org/python/core/PyFrozenSetDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyFunction.java b/src/org/python/core/PyFunction.java index 11353c216..5c05ed009 100644 --- a/src/org/python/core/PyFunction.java +++ b/src/org/python/core/PyFunction.java @@ -273,20 +273,23 @@ public PyObject fastGetDict() { return __dict__; } + @Override @ExposedGet(name = "__dict__") public PyObject getDict() { ensureDict(); return __dict__; } + @Override @ExposedSet(name = "__dict__") public void setDict(PyObject value) { - if (!(value instanceof PyDictionary) && !(value instanceof PyStringMap)) { + if (!(value instanceof AbstractDict)) { throw Py.TypeError("setting function's dictionary to a non-dict"); } __dict__ = value; } + @Override @ExposedDelete(name = "__dict__") public void delDict() { throw Py.TypeError("function's dictionary may not be deleted"); @@ -482,6 +485,16 @@ public PyObject __call__(ThreadState state, PyObject arg1, PyObject[] args, return __code__.call(state, arg1, args, keywords, __globals__, __defaults__, __closure__); } + @Override + public PyString __repr__() { + return function___repr__(); + } + + @ExposedMethod(doc = BuiltinDocs.buffer___repr___doc) + final PyString function___repr__() { + return Py.newString(toString()); + } + @Override public String toString() { return String.format("", __name__, Py.idstr(this)); @@ -525,6 +538,7 @@ private Object proxy( Class c ) { return Proxy.newProxyInstance(c.getClassLoader(), new Class[]{c}, this); } + @Override public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable { // Handle invocation when invoked through Proxy (as coerced to single method interface) if (method.getDeclaringClass() == Object.class) { @@ -583,7 +597,7 @@ public int traverse(Visitproc visit, Object arg) { if (retVal != 0) { return retVal; } - + // CPython also traverses the name, which is not stored // as a PyObject in Jython: // Py_VISIT(f->func_name); diff --git a/src/org/python/core/PyGenerator.java b/src/org/python/core/PyGenerator.java index fa007bc03..a76e849d6 100644 --- a/src/org/python/core/PyGenerator.java +++ b/src/org/python/core/PyGenerator.java @@ -33,6 +33,11 @@ public PyGenerator(PyFrame frame, PyObject closure) { FinalizeTrigger.ensureFinalizer(this); } + @ExposedGet(name = "__name__") + public String getName() { + return gi_code.co_name; + } + public PyObject send(PyObject value) { return generator_send(value); } @@ -172,6 +177,16 @@ public PyObject __iternext__(ThreadState state) { return result; } + @Override + public String toString() { + return generator_toString(); + } + + @ExposedMethod(names = "__repr__") + final String generator_toString() { + return String.format("", getName(), Py.idstr(this)); + } + /* Traverseproc implementation */ @Override diff --git a/src/org/python/core/PyInstance.java b/src/org/python/core/PyInstance.java index 4d44a54d0..a7dad1d48 100644 --- a/src/org/python/core/PyInstance.java +++ b/src/org/python/core/PyInstance.java @@ -52,7 +52,7 @@ public static PyObject instance___new__(PyNewWrapper new_, boolean init, PyType PyObject dict = ap.getPyObject(1, Py.None); if (dict == Py.None) { dict = null; - } else if (!(dict instanceof PyStringMap || dict instanceof PyDictionary)) { + } else if (!(dict instanceof AbstractDict)) { throw Py.TypeError("instance() second arg must be dictionary or None"); } return new PyInstance(klass, dict); diff --git a/src/org/python/core/PyInteger.java b/src/org/python/core/PyInteger.java index 493f410e0..5a4d1268c 100644 --- a/src/org/python/core/PyInteger.java +++ b/src/org/python/core/PyInteger.java @@ -117,8 +117,8 @@ public static PyObject int_new(PyNewWrapper new_, boolean init, PyType subtype, * * @param x to convert to an int * @return int or long result. - * @throws PyException (TypeError) if no method of conversion can be found - * @throws PyException (AttributeError) if neither __int__ nor __trunc__ found (?) + * @throws PyException {@code TypeError} if no method of conversion can be found + * @throws PyException {@code AttributeError} if neither __int__ nor __trunc__ found (?) */ private static PyObject asPyInteger(PyObject x) throws PyException { // XXX: Not sure that this perfectly matches CPython semantics. @@ -226,27 +226,27 @@ final boolean int___nonzero__() { public Object __tojava__(Class c) { if (c == Integer.TYPE || c == Number.class || c == Object.class || c == Integer.class || c == Serializable.class) { - return new Integer(getValue()); + return Integer.valueOf(getValue()); } if (c == Boolean.TYPE || c == Boolean.class) { - return new Boolean(getValue() != 0); + return Boolean.valueOf(getValue() != 0); } if (c == Byte.TYPE || c == Byte.class) { - return new Byte((byte)getValue()); + return Byte.valueOf((byte)getValue()); } if (c == Short.TYPE || c == Short.class) { - return new Short((short)getValue()); + return Short.valueOf((short)getValue()); } if (c == Long.TYPE || c == Long.class) { - return new Long(getValue()); + return Long.valueOf(getValue()); } if (c == Float.TYPE || c == Float.class) { - return new Float(getValue()); + return Float.valueOf(getValue()); } if (c == Double.TYPE || c == Double.class) { - return new Double(getValue()); + return Double.valueOf(getValue()); } return super.__tojava__(c); } @@ -1062,7 +1062,7 @@ final PyObject int___format__(PyObject formatSpec) { * * @param spec a parsed PEP-3101 format specification. * @return a formatter ready to use, or null if the type is not an integer format type. - * @throws PyException(ValueError) if the specification is faulty. + * @throws PyException {@code ValueError} if the specification is faulty. */ @SuppressWarnings("fallthrough") static IntegerFormatter prepareFormatter(Spec spec) throws PyException { diff --git a/src/org/python/core/PyIntegerDerived.java b/src/org/python/core/PyIntegerDerived.java index 4198fc9d7..b8ea28121 100644 --- a/src/org/python/core/PyIntegerDerived.java +++ b/src/org/python/core/PyIntegerDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyJavaPackage.java b/src/org/python/core/PyJavaPackage.java index d5c7c562a..4a9b96302 100644 --- a/src/org/python/core/PyJavaPackage.java +++ b/src/org/python/core/PyJavaPackage.java @@ -4,50 +4,41 @@ package org.python.core; import org.python.core.packagecache.PackageManager; -import java.util.StringTokenizer; -/** - * A representation of java package. - */ +import java.util.Collection; + +/** A representation of java package. */ public class PyJavaPackage extends PyObject implements Traverseproc { - public String __name__; + public String __name__; public PyStringMap __dict__; - /** Its keys are the names of statically known classes. - * E.g. from jars pre-scan. - */ + /** Its keys are the names of statically known classes. E.g. from jars pre-scan. */ public PyStringMap clsSet; public String __file__; - /** (Control) package manager whose hierarchy contains this java pkg. - */ + /** (Control) package manager whose hierarchy contains this java pkg */ public PackageManager __mgr__; public PyJavaPackage(String name) { this(name, null, null); } - public PyJavaPackage(String name,String jarfile) { + public PyJavaPackage(String name, String jarfile) { this(name, null, jarfile); } - public PyJavaPackage(String name,PackageManager mgr) { + public PyJavaPackage(String name, PackageManager mgr) { this(name, mgr, null); } - - public PyJavaPackage(String name,PackageManager mgr,String jarfile) { + public PyJavaPackage(String name, PackageManager mgr, String jarfile) { __file__ = jarfile; __name__ = name; + __mgr__ = (mgr != null) ? mgr : PySystemState.packageManager; - if( mgr == null ) - __mgr__ = PySystemState.packageManager; // default - else - __mgr__ = mgr; - - clsSet= new PyStringMap(); + clsSet = new PyStringMap(); __dict__ = new PyStringMap(); __dict__.__setitem__("__name__", new PyString(__name__)); @@ -57,29 +48,39 @@ public PyJavaPackage addPackage(String name) { return addPackage(name, null); } + /** + * From a dotted package name {@code a.b.c} interpreted relative to this package {@code t}, + * ensure that {@code a} is in the dictionary of {@code t} and then recursively process the + * remainder {@code b.c} relative to {@code a}, finally returning the {@link #PyJavaPackage} of + * {@code t.a.b.c}. In the case where the initial package name is just {@code a}, no dots, the + * method simply ensures {@code a} is entered in {@code t}, and returns the + * {@link PyJavaPackage} of {@code t.a}. + * + * @param name a package name + * @param jarfile becomes the {@code __file__} attribute + * @return the {@link PyJavaPackage} of the package named + */ public PyJavaPackage addPackage(String name, String jarfile) { int dot = name.indexOf('.'); - String firstName=name; - String lastName=null; + String firstName = name; + String remainder = null; if (dot != -1) { - firstName = name.substring(0,dot); - lastName = name.substring(dot+1, name.length()); + firstName = name.substring(0, dot); + remainder = name.substring(dot + 1, name.length()); } firstName = firstName.intern(); - PyJavaPackage p = (PyJavaPackage)__dict__.__finditem__(firstName); + PyJavaPackage p = (PyJavaPackage) __dict__.__finditem__(firstName); if (p == null) { - String pname = __name__.length() == 0 ? - firstName : __name__+'.'+firstName; + String pname = __name__.length() == 0 ? firstName : __name__ + '.' + firstName; p = new PyJavaPackage(pname, __mgr__, jarfile); __dict__.__setitem__(firstName, p); } else { - // this code is ok here, because this is not needed for - // a top level package - if (jarfile == null || !jarfile.equals(p.__file__)) + // this code is ok here, because this is not needed for a top level package + if (jarfile == null || !jarfile.equals(p.__file__)) { p.__file__ = null; + } } - if (lastName != null) return p.addPackage(lastName, jarfile); - else return p; + return remainder != null ? p.addPackage(remainder, jarfile) : p; } public PyObject addClass(String name, Class c) { @@ -89,23 +90,23 @@ public PyObject addClass(String name, Class c) { } /** - * Add statically known classes. + * Add the classes named to this package, but with only a placeholder value. These names are + * statically known, typically from processing JAR files on the class path. * - * @param classes - * their names as comma-separated string + * @param classes the names as strings */ - public void addPlaceholders(String classes) { - StringTokenizer tok = new StringTokenizer(classes, ",@"); - while (tok.hasMoreTokens()) { - String p = tok.nextToken(); - String name = p.trim().intern(); - if (clsSet.__finditem__(name) == null) + public void addPlaceholders(Collection classes) { + for (String name : classes) { + name = name.intern(); + if (clsSet.__finditem__(name) == null) { clsSet.__setitem__(name, Py.One); + } } } + @Override public PyObject __dir__() { - return __mgr__.doDir(this,false,false); + return __mgr__.doDir(this, false, false); } /** @@ -117,74 +118,78 @@ public PyObject __dir__() { * @return list of member names */ public PyObject fillDir() { - return __mgr__.doDir(this,true,false); + return __mgr__.doDir(this, true, false); } - + @Override public PyObject __findattr_ex__(String name) { PyObject ret = __dict__.__finditem__(name); - if (ret != null) return ret; - - if (__mgr__.packageExists(__name__,name)) { - __mgr__.notifyPackageImport(__name__,name); - return addPackage(name); - } - Class c = __mgr__.findClass(__name__,name); - if (c != null) return addClass(name,c); + if (ret != null) { + return ret; - if (name == "__name__") return new PyString(__name__); - if (name == "__dict__") return __dict__; - if (name == "__mgr__") return Py.java2py(__mgr__); - if (name == "__file__") { - if (__file__ != null) return new PyString(__file__); + } else if (__mgr__.packageExists(__name__, name)) { + __mgr__.notifyPackageImport(__name__, name); + return addPackage(name); - return Py.None; + } else { + Class c = __mgr__.findClass(__name__, name); + if (c != null) { + return addClass(name, c); + } else if (name == "__name__") { + return new PyString(__name__); + } else if (name == "__dict__") { + return __dict__; + } else if (name == "__mgr__") { + return Py.java2py(__mgr__); + } else if (name == "__file__") { + // Stored as UTF-16 for Java but expected as bytes in Python + return __file__ == null ? Py.None : Py.fileSystemEncode(__file__); + } else { + return null; + } } - - return null; } + @Override public void __setattr__(String attr, PyObject value) { if (attr == "__mgr__") { - PackageManager newMgr = Py.tojava(value, - PackageManager.class); + PackageManager newMgr = Py.tojava(value, PackageManager.class); if (newMgr == null) { throw Py.TypeError("cannot set java package __mgr__ to None"); } __mgr__ = newMgr; - return; - } - if (attr == "__file__") { - __file__ = value.__str__().toString(); - return; + } else if (attr == "__file__") { + // Stored as UTF-16 for Java but presented as bytes from Python + __file__ = Py.fileSystemDecode(value); + } else { + super.__setattr__(attr, value); } - - super.__setattr__(attr,value); } - public String toString() { - return ""; + @Override + public String toString() { + return ""; } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { - //__dict__ cannot be null + // __dict__ cannot be null int retVal = visit.visit(__dict__, arg); if (retVal != 0) { return retVal; + } else { + // clsSet cannot be null + retVal = visit.visit(clsSet, arg); + if (retVal != 0) { + return retVal; + } else { + // __mgr__ and __mgr__.topLevelPackage cannot be null + return visit.visit(__mgr__.topLevelPackage, arg); + } } - - //clsSet cannot be null - retVal = visit.visit(clsSet, arg); - if (retVal != 0) { - return retVal; - } - //__mgr__ and __mgr__.topLevelPackage cannot be null - return visit.visit(__mgr__.topLevelPackage, arg); } @Override diff --git a/src/org/python/core/PyJavaType.java b/src/org/python/core/PyJavaType.java index a2f879623..9a62722d1 100644 --- a/src/org/python/core/PyJavaType.java +++ b/src/org/python/core/PyJavaType.java @@ -1,5 +1,10 @@ +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; +import org.python.core.util.StringUtil; +import org.python.util.Generic; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -10,11 +15,16 @@ import java.io.ObjectStreamClass; import java.io.OutputStream; import java.io.Serializable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles.Lookup; +import java.lang.invoke.MethodType; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -22,36 +32,38 @@ import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.Stack; -import org.python.core.util.StringUtil; -import org.python.util.Generic; - - public class PyJavaType extends PyType { private final static Class[] OO = {PyObject.class, PyObject.class}; + // @formatter:off /** Deprecated methods in java.awt.* that have bean property equivalents we prefer. */ - private final static Set BAD_AWT_METHODS = Generic.set("layout", - "insets", - "size", - "minimumSize", - "preferredSize", - "maximumSize", - "bounds", - "enable"); - - - // Add well-known immutable classes from standard packages of - // java.lang, java.net, java.util that are not marked Cloneable. - // This was found by hand, there are likely more! + private final static Set BAD_AWT_METHODS = Generic.set( + "layout", + "insets", + "size", + "minimumSize", + "preferredSize", + "maximumSize", + "bounds", + "enable"); + // @formatter:on + /* + * Add well-known immutable classes from standard packages of java.lang, java.net, java.util + * that are not marked Cloneable. This was found by hand, there are likely more! + */ + // @formatter:off private final static Set> immutableClasses = Generic.set( Boolean.class, Byte.class, @@ -70,7 +82,24 @@ public class PyJavaType extends PyType { java.net.Proxy.class, java.net.URI.class, java.util.concurrent.TimeUnit.class); + // @formatter:on + + /** + * Constant PyJavaTypes used frequently. The inner class pattern ensures they can + * be constructed before PyJavaType is initialised, and a unique instance of + * type(Class) exists for {@link PyJavaType#PyJavaType(Class, boolean)} to use. + */ + static class Constant extends PyType.Constant { + + // Note that constructing type(Class.class) does not register it in the type system. + static final PyType CLASS = new PyJavaType(false); + static final PyType OBJECT = fromClass(Object.class); + } + static { + // Ensure that type(Class.class) is registered in the type system + fromClass(Class.class); + } /** * Other Java classes this type has MRO conflicts with. This doesn't matter for Java method @@ -86,25 +115,75 @@ public class PyJavaType extends PyType { private Set modified; public static PyObject wrapJavaObject(Object o) { - PyObject obj = new PyObjectDerived(PyType.fromClass(o.getClass(), false)); - JyAttribute.setAttr(obj, JyAttribute.JAVA_PROXY_ATTR, o); + PyObject obj = new PyObjectDerived(fromClass(o.getClass())); + setProxyAttr(obj, o); return obj; } + /** + * Create a Python type for a Java class that does not descend from PyObject. (This will be + * indicated by a null {@link PyType#underlying_class}.) + */ public PyJavaType() { - super(TYPE == null ? fromClass(PyType.class) : TYPE); + super(Constant.PYTYPE); + } + + /** + * Create a Python type for a Java class that is not exposed, but may descend from + * PyObject. This ancestry, implicit in the argument, makes a big difference when a + * subsequent {@link #init(Set)} is called. + *

    + * If the class descends from PyObject, it records the class it represents in + * {@link PyType#underlying_class}. Otherwise, it records the class it represents in the + * attribute {@link JyAttribute#JAVA_PROXY_ATTR}, and is said to be a proxy for it. In either + * case {@link PyType#builtin} is true. + * + * @param c Java class for which this is a Python type. + */ + PyJavaType(Class c) { + this(c, PyObject.class.isAssignableFrom(c)); + } + + /** + * Create a Python type object for a given Java class that is not an exposed type, + * but may still be a PyObject. This implements {@link #PyJavaType(Class)}, which + * works it out from the class, but may be called directly when you already know which case + * you're in. + * + * @param c Java class for which this is a Python type. + * @param isPyObject true iff the class descends from PyObject + */ + PyJavaType(Class c, boolean isPyObject) { + // A little messy as the super call must come first. + super(isPyObject ? Constant.PYTYPE : Constant.CLASS, isPyObject ? c : null); + // And if this is not for a PyObject : + if (!isPyObject) { + setProxyAttr(this, c); + } + } + + /** + * Create the PyJavaType instance (proxy) for java.lang.Class itself. + * The argument just exists to give the constructor a distinct signature. The + * {@link #underlying_class} is null, and it is a built-in. + */ + PyJavaType(boolean ignored) { + // Use the special super constructor. + super(true); + setProxyAttr(this, Class.class); } @Override protected boolean useMetatypeFirst(PyObject attr) { - return !(attr instanceof PyReflectedField || attr instanceof PyReflectedFunction || - attr instanceof PyBeanEventProperty); + return !(attr instanceof PyReflectedField || attr instanceof PyReflectedFunction + || attr instanceof PyBeanEventProperty); } // Java types are ok with things being added and removed from their dicts as long as there isn't @Override void type___setattr__(String name, PyObject value) { - PyObject field = lookup(name);// If we have a static field that takes this, go with that + PyObject field = lookup(name); + // If we have a static field that takes this, go with that if (field != null) { if (field._doset(null, value)) { return; @@ -133,7 +212,7 @@ void type___setattr__(String name, PyObject value) { void type___delattr__(String name) { PyObject field = lookup(name); if (field == null) { - throw Py.NameError("attribute not found: "+name); + throw Py.NameError("attribute not found: " + name); } if (!field.jdontdel()) { object___delattr__(name); @@ -144,64 +223,110 @@ void type___delattr__(String name) { postDelattr(name); } + /** + * {@inheritDoc} + *

    + * An override specifically for Java classes (that are not {@link PyObject}) has the possibility + * of completing the MRO in {@code mro}, by additional steps affecting the {@code mro} and + * {@code toMerge} passed in. This divergence from the Python rules is acceptable for Java. + */ @Override void handleMroError(MROMergeState[] toMerge, List mro) { + if (underlying_class != null) { - // If this descends from PyObject, don't do the Java mro cleanup + // This descends from PyObject (but is not exposed): don't attempt recovery. super.handleMroError(toMerge, mro); } - Set inConflict = Generic.set(); - PyJavaType winner = null; + + // Make a set of all the PyJavaTypes still in the lists to merge. + Set inConflict = new LinkedHashSet<>(); for (MROMergeState mergee : toMerge) { for (int i = mergee.next; i < mergee.mro.length; i++) { - if (mergee.mro[i] == PyObject.TYPE - || mergee.mro[i] == PyType.fromClass(Object.class)) { - continue; - } - if (winner == null) { - // Pick an arbitrary class to be added to the mro next and break the conflict. - // If method name conflicts were allowed between methods added to Java types, - // it would go first, but that's prevented, so being a winner doesn't actually - // get it anything - winner = (PyJavaType)mergee.mro[i]; + PyObject m = mergee.mro[i]; + if (m instanceof PyJavaType && m != Constant.OBJECT) { + inConflict.add((PyJavaType) m); } - inConflict.add((PyJavaType)mergee.mro[i]); } } - Set allModified = Generic.set(); - PyJavaType[] conflictedAttributes = inConflict.toArray(new PyJavaType[inConflict.size()]); - for (PyJavaType type : conflictedAttributes) { - if (type.modified == null) { - continue; - } - for (String method : type.modified) { - if (!allModified.add(method)) { // Another type in conflict has this method, possibly fail - PyList types = new PyList(); - Set proxySet = Generic.set(); - for (PyJavaType othertype : conflictedAttributes) { - if (othertype.modified != null && othertype.modified.contains(method)) { - types.add(othertype); - proxySet.add(othertype.getProxyType()); + /* + * Collect the names of all the methods added to any of these types (with certain + * exclusions) that occur in more than one of these residual types. If a name is found in + * more than one of these types, raise an error. + */ + Set allModified = new HashSet<>(); + for (PyJavaType type : inConflict) { + if (type.modified != null) { + // For every method name modified in type ... + for (String method : type.modified) { + if (!allModified.add(method)) { + /* + * The method name was already in the set, so has appeared already. Work out + * which one that was by rescanning. + */ + List types = new ArrayList<>(); + Set> proxySet = new HashSet<>(); + Class proxyType = type.getProxyType(); + for (PyJavaType othertype : inConflict) { + /* + * Ignore any pairings of types that are in a superclass/superinterface + * relationship with each other. This problem is a false positive that + * happens because of the automatic addition of methods so that Java + * classes behave more like their corresponding Python types, such as + * adding sort or remove. See http://bugs.jython.org/issue2445 + */ + if (othertype.modified != null && othertype.modified.contains(method)) { + Class otherProxyType = othertype.getProxyType(); + if (otherProxyType.isAssignableFrom(proxyType)) { + continue; + } else if (proxyType.isAssignableFrom(otherProxyType)) { + continue; + } else { + types.add(othertype); + proxySet.add(otherProxyType); + } + } + } + + /* + * Need to special case __iter__ in certain circumstances to ignore the + * conflict in having duplicate __iter__ added (see getCollectionProxies), + * while still allowing each path on the inheritance hierarchy to get an + * __iter__. Annoying but necessary logic. + */ + if (method.equals("__iter__")) { + if (Generic.set(Iterable.class, Map.class).containsAll(proxySet)) { + /* + * Need to special case __iter__ in collections that implement both + * Iterable and Map. See http://bugs.jython.org/issue1878 + */ + continue; + } else if (Generic.set(Iterator.class, Enumeration.class) + .containsAll(proxySet)) { + /* + * Need to special case __iter__ in iterators that Iterator and + * Enumeration. Annoying but necessary logic. See + * http://bugs.jython.org/issue2445 + */ + continue; + } + } + + String fmt = "Supertypes that share a modified attribute " + + "have an MRO conflict[attribute=%s, supertypes=%s, type=%s]"; + if (types.size() > 0) { + throw Py.TypeError(String.format(fmt, method, types, this.getName())); } } - // Need to special case collections that implement both Iterable and Map. Ignore the conflict - // in having duplicate __iter__ added (see getCollectionProxies), while still allowing each - // path on the inheritance hierarchy to get an __iter__. Annoying but necessary logic. - // See http://bugs.jython.org/issue1878 - if (method.equals("__iter__") && proxySet.equals(Generic.set(Iterable.class, Map.class))) { - continue; - } - throw Py.TypeError(String.format("Supertypes that share a modified attribute " - + "have an MRO conflict[attribute=%s, supertypes=%s, type=%s]", - method, types, this.getName())); } } } - // We can keep trucking, there aren't any existing method name conflicts. Mark the - // conflicts in all the classes so further method additions can check for trouble - for (PyJavaType type : conflictedAttributes) { + /* + * We can keep trucking, there aren't any existing method name conflicts. Mark the conflicts + * in all the classes so further method additions can check for trouble. + */ + for (PyJavaType type : inConflict) { for (PyJavaType otherType : inConflict) { if (otherType != type) { if (type.conflicted == null) { @@ -212,228 +337,532 @@ void handleMroError(MROMergeState[] toMerge, List mro) { } } - // Add our winner to the mro, clear the clog, and try to finish the rest + /* + * Emit the first conflicting type we encountered to the MRO, and remove it from the working + * lists. Forcing a step like this is ok for classes compiled from Java as the order of + * bases is not significant as long as hierarchy is preserved. + */ + PyJavaType winner = inConflict.iterator().next(); mro.add(winner); for (MROMergeState mergee : toMerge) { mergee.removeFromUnmerged(winner); } + + // Restart the MRO generation algorithm from the current state. computeMro(toMerge, mro); } + /** + * Complete the initialisation of the PyType for non-exposed PyObject + * or any other Java class for which we need a Python type object. This call will + * fill {@link #dict}, {@link #name} and all other descriptive state using characteristics of + * the class obtained by reflection. + *

    + * Where the class is not a PyObject at all, the method registers all the "visible + * bases" (according to Java) of the class represented, which will result in further calls to + * register their visible bases in turn. In the process, this method, recursively, saves this + * and the PyJavaTypes of further non-PyObject bases into into + * needsInners, so that these may be processed later. + * + * @param needsInners collects PyJavaTypes that need further processing + */ @Override - protected void init(Class forClass, Set needsInners) { + protected void init(Set needsInners) { + + // Get the class for which the type is to be initialised. + Class forClass = underlying_class != null ? underlying_class : getProxyType(); name = forClass.getName(); + // Strip the java fully qualified class name from Py classes in core if (name.startsWith("org.python.core.Py")) { name = name.substring("org.python.core.Py".length()).toLowerCase(); } dict = new PyStringMap(); + Class baseClass = forClass.getSuperclass(); - if (PyObject.class.isAssignableFrom(forClass)) { - // Non-exposed subclasses of PyObject use a simple linear mro to PyObject that ignores - // their interfaces - underlying_class = forClass; + + if (underlying_class != null) { + /* + * Although not exposed, this is a subclass of PyObject, so it uses a simple linear mro + * to PyObject that ignores interfaces. + */ computeLinearMro(baseClass); + } else { + /* + * This is a wrapped Java type: fill in the mro first with the interfaces then the + * superclass. + */ needsInners.add(this); - JyAttribute.setAttr(this, JyAttribute.JAVA_PROXY_ATTR, forClass); - objtype = PyType.fromClassSkippingInners(Class.class, needsInners); - // Wrapped Java types fill in their mro first using all of their interfaces then their - // super class. - List visibleBases = Generic.list(); + LinkedList visibleBases = new LinkedList<>(); for (Class iface : forClass.getInterfaces()) { if (iface == PyProxy.class || iface == ClassDictInit.class) { - // Don't show the interfaces added by proxy type construction; otherwise Python - // subclasses of proxy types and another Java interface can't make a consistent - // mro + /* + * Don't show the interfaces added by proxy type construction; otherwise Python + * subclasses of proxy types and another Java interface can't make a consistent + * mro. + */ continue; } if (baseClass != null && iface.isAssignableFrom(baseClass)) { - // Don't include redundant interfaces. If the redundant interface has methods - // that were combined with methods of the same name from other interfaces higher - // in the hierarchy, adding it here hides the forms from those interfaces. + /* + * Don't include redundant interfaces. If the redundant interface has methods + * that were combined with methods of the same name from other interfaces higher + * in the hierarchy, adding it here hides the forms from those interfaces. + */ continue; } - visibleBases.add(PyType.fromClassSkippingInners(iface, needsInners)); + visibleBases.add(fromClass(iface)); } - Object javaProxy = JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR); + if (forClass == Object.class) { + base = Constant.PYOBJECT; + } else if (baseClass == null) { + /* + * It would be most like Java to have no base (like PyNone) but in that case, the + * MRO calculation puts Object ahead of the interface. Our patching of Java + * container interfaces to behave like Python container objects requires the + * opposite. + */ + base = Constant.OBJECT; + } else if (forClass == Class.class) { + base = Constant.PYTYPE; + } else { + base = fromClass(baseClass); + } - if (javaProxy == Object.class) { - base = PyType.fromClassSkippingInners(PyObject.class, needsInners); - } else if(baseClass == null) { - base = PyType.fromClassSkippingInners(Object.class, needsInners); - } else if (javaProxy == Class.class) { - base = PyType.fromClassSkippingInners(PyType.class, needsInners); + if (baseClass == null) { + // Object, an interface, a primitive or void: base goes last. + visibleBases.add(base); } else { - base = PyType.fromClassSkippingInners(baseClass, needsInners); + // forClass represents a (concrete or abstract) class: base comes before interfaces. + visibleBases.push(base); } - visibleBases.add(base); + this.bases = visibleBases.toArray(new PyObject[visibleBases.size()]); mro = computeMro(); } - // PyReflected* can't call or access anything from non-public classes that aren't in - // org.python.core - if (!Modifier.isPublic(forClass.getModifiers()) && - !name.startsWith("org.python.core") && Options.respectJavaAccessibility) { + /* + * PyReflected* can't call or access anything from non-public classes that aren't in + * org.python.core + */ + if (!isAccessibleClass(forClass) && !name.startsWith("org.python.core")) { handleSuperMethodArgCollisions(forClass); return; } - // Add methods and determine bean properties declared on this class - Map props = Generic.map(); - Map events = Generic.map(); + /* + * Compile lists of the methods, fields and constructors to be exposed through this type. If + * we respect Java accessibility, this is simple. + */ Method[] methods; + Field[] fields; + Constructor[] constructors; + if (Options.respectJavaAccessibility) { - // returns just the public methods + // Just the public methods, fields and constructors methods = forClass.getMethods(); + fields = forClass.getFields(); + constructors = forClass.getConstructors(); + } else { - // Grab all methods on this class and all of its superclasses and make them accessible + // All methods on this class and all of its super classes List allMethods = Generic.list(); - for(Class c = forClass; c != null; c = c.getSuperclass()) { + for (Class c = forClass; c != null; c = c.getSuperclass()) { for (Method meth : c.getDeclaredMethods()) { allMethods.add(meth); meth.setAccessible(true); } } methods = allMethods.toArray(new Method[allMethods.size()]); + + // All the fields on just this class + fields = forClass.getDeclaredFields(); + for (Field field : fields) { + field.setAccessible(true); + } + + // All the constructors (except if this is for class Class) + if (forClass == Class.class) { + // No matter the security manager, cannot set constructors accessible + constructors = forClass.getConstructors(); + } else { + constructors = forClass.getDeclaredConstructors(); + for (Constructor ctr : constructors) { + ctr.setAccessible(true); + } + } } - /* make sure we "sort" all methods so they resolve in the right order. See #2391 for details */ + // Methods must be in resolution order. See issue bjo #2391 for detail. Arrays.sort(methods, new MethodComparator(new ClassComparator())); + // Add methods, also accumulating them in reflectedFuncs, and spotting Java Bean members. + ArrayList reflectedFuncs = new ArrayList<>(methods.length); + Map props = Generic.map(); + Map> events = Generic.map(); + + // First pass skip inherited (and certain "ignored") methods. + addMethods(baseClass, reflectedFuncs, props, events, methods); + // Add inherited and previously ignored methods + addInheritedMethods(reflectedFuncs, methods); + + // Add fields declared on this type + addFields(baseClass, fields); + + // Fill in the bean events and properties picked up while going through the methods + addBeanEvents(events); + addBeanProperties(props); + + // Add constructors declared on this type + addConstructors(forClass, constructors); + + // Special handling for Java collection types + addCollectionProxies(forClass); + + // Handle classes that use the ClassDictInit pattern for their definition + PyObject nameSpecified = null; + if (ClassDictInit.class.isAssignableFrom(forClass) && forClass != ClassDictInit.class) { + try { + Method m = forClass.getMethod("classDictInit", PyObject.class); + m.invoke(null, dict); + // allow the class to override its name after it is loaded + nameSpecified = dict.__finditem__("__name__"); + if (nameSpecified != null) { + name = nameSpecified.toString(); + } + } catch (Exception exc) { + throw Py.JavaError(exc); + } + } + + // Fill in the __module__ attribute of PyReflectedFunctions. + if (reflectedFuncs.size() > 0) { + if (nameSpecified == null) { + nameSpecified = Py.newString(name); + } + for (PyReflectedFunction func : reflectedFuncs) { + func.__module__ = nameSpecified; + } + } + + // Handle descriptor classes + if (baseClass != Object.class) { + hasGet = getDescrMethod(forClass, "__get__", OO) != null + || getDescrMethod(forClass, "_doget", PyObject.class) != null + || getDescrMethod(forClass, "_doget", OO) != null; + hasSet = getDescrMethod(forClass, "__set__", OO) != null + || getDescrMethod(forClass, "_doset", OO) != null; + hasDelete = getDescrMethod(forClass, "__delete__", PyObject.class) != null + || getDescrMethod(forClass, "_dodel", PyObject.class) != null; + } + + /* + * Certain types get particular implementations of__lt__, __le__, __ge__, __gt__, __copy__ + * and __deepcopy__. + */ + if (forClass == Object.class) { + addMethodsForObject(); + } else if (forClass == Comparable.class) { + addMethodsForComparable(); + } else if (forClass == Cloneable.class) { + addMethodsForCloneable(); + } else if (forClass == Serializable.class) { + addMethodsForSerializable(); + } else if (immutableClasses.contains(forClass)) { + // __deepcopy__ just works for these objects since it uses serialization instead + addMethod(new PyBuiltinMethodNarrow("__copy__") { + + @Override + public PyObject __call__() { + return self; + } + }); + } + } + + /** + * A class containing a test that a given class is accessible to Jython, in the Modular Java + * sense. It is in its own class simply to contain the state we need and its messy + * initialisation. + */ + private static class Modular { + + private static final Lookup LOOKUP = MethodHandles.lookup(); + + /** + * Test we need is constructed as a method handle, reflectively (so it works on Java less + * than 9). + */ + private static final MethodHandle accessibleMH; + static { + MethodHandle acc; + try { + Class moduleClass = Class.forName("java.lang.Module"); + // mod = λ(c) c.getModule() : Class → Module + MethodHandle mod = LOOKUP.findVirtual(Class.class, "getModule", + MethodType.methodType(moduleClass)); + // pkg = λ(c) c.getPackageName() : Class → String + MethodHandle pkg = LOOKUP.findVirtual(Class.class, "getPackageName", + MethodType.methodType(String.class)); + // exps = λ(m, pn) m.isExported(pn) : Module, String → boolean + MethodHandle exps = LOOKUP.findVirtual(moduleClass, "isExported", + MethodType.methodType(boolean.class, String.class)); + // expc = λ(m, c) exps(m, pkg(c)) : Module, Class → boolean + MethodHandle expc = MethodHandles.filterArguments(exps, 1, pkg); + // acc = λ(c) expc(mod(c), c) : Class → boolean + acc = MethodHandles.foldArguments(expc, mod); + } catch (ReflectiveOperationException | SecurityException e) { + // Assume not a modular Java platform: acc = λ(c) true : Class → boolean + acc = MethodHandles.dropArguments(MethodHandles.constant(boolean.class, true), 0, + Class.class); + } + accessibleMH = acc; + } + + /** + * Test whether a given class is in a package exported (accessible) to Jython, in the + * Modular Java sense. Jython code is all in the unnamed module, so in fact we are testing + * accessibility to the package of the class. + * + * If this means nothing on this platform (if the classes and methods needed are not found), + * decide that we are not on a modular platform, in which case all invocations return + * true. + * + * @param c the class + * @return true iff accessible to Jython + */ + static boolean accessible(Class c) { + try { + return (boolean) accessibleMH.invokeExact(c); + } catch (Throwable e) { + return true; + } + } + } + + /** + * Test whether a given class is accessible, meaning it is in a package exported to Jython and + * public (or we are ignoring accessibility). + * + * @param c the class + * @return true iff accessible to Jython + */ + static boolean isAccessibleClass(Class c) { + if (!Modular.accessible(c)) { + return false; + } else { + return !Options.respectJavaAccessibility || Modifier.isPublic(c.getModifiers()); + } + } + + /** + * Add descriptors to this type's dictionary ({@code __dict__}) for methods defined on the + * target class itself (the {@code fromClass}), where not inherited. One descriptor is created + * for each simple name and a signature for every method with that simple name is added to the + * descriptor. See also {@link #addInheritedMethods(List, Method[])}. This is exclusively a + * helper method for {@link #init(Set)}. + * + * @param baseClass ancestor of the target class + * @param reflectedFuncs to which reflected functions are added for further processing + * @param props to which Java Bean properties are added for further processing + * @param events to which Java Bean events are added for further processing + * @param methods of the target class + */ + private void addMethods(Class baseClass, List reflectedFuncs, + Map props, Map> events, + Method[] methods) { + boolean isInAwt = name.startsWith("java.awt.") && name.indexOf('.', 9) == -1; + for (Method meth : methods) { - if (!declaredOnMember(baseClass, meth) || ignore(meth)) { + if (!declaredHere(baseClass, meth) || ignore(meth)) { continue; } String methname = meth.getName(); - // Special case a few troublesome methods in java.awt.*. These methods are all - // deprecated and interfere too badly with bean properties to be tolerated. This is - // totally a hack but a lot of code that uses java.awt will break without it. + /* + * Special case a few troublesome methods in java.awt.*. These methods are all + * deprecated and interfere too badly with bean properties to be tolerated. This is + * totally a hack but a lot of code that uses java.awt will break without it. + */ if (isInAwt && BAD_AWT_METHODS.contains(methname)) { continue; } String nmethname = normalize(methname); - PyReflectedFunction reflfunc = (PyReflectedFunction)dict.__finditem__(nmethname); + + PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname); if (reflfunc == null) { - dict.__setitem__(nmethname, new PyReflectedFunction(meth)); + // A new descriptor is required + reflfunc = new PyReflectedFunction(meth); + reflectedFuncs.add(reflfunc); + dict.__setitem__(nmethname, reflfunc); } else { + // A descriptor for the same simple name exists: add a signature to it. reflfunc.addMethod(meth); } - // Now check if this is a bean method, for which it must be an instance method - if (Modifier.isStatic(meth.getModifiers())) { - continue; - } + // Check if this is a Java Bean method, indicating the "bean nature" of the class + checkBeanMethod(props, events, meth); + } + } - // First check if this is a bean event addition method - int n = meth.getParameterTypes().length; - if ((methname.startsWith("add") || methname.startsWith("set")) - && methname.endsWith("Listener") && n == 1 && - meth.getReturnType() == Void.TYPE && - EventListener.class.isAssignableFrom(meth.getParameterTypes()[0])) { - Class eventClass = meth.getParameterTypes()[0]; - String ename = eventClass.getName(); - int idot = ename.lastIndexOf('.'); - if (idot != -1) { - ename = ename.substring(idot + 1); - } - ename = normalize(StringUtil.decapitalize(ename)); - events.put(ename, new PyBeanEvent(ename, eventClass, meth)); - continue; + /** + * Consider whether the given method of the current class indicates the existence of a JavaBean + * property or event. + * + * @param props in which to store properties we discover + * @param events in which to store events we discover + * @param meth under consideration + */ + private void checkBeanMethod(Map props, + Map> events, Method meth) { + + // If this is a bean method at all, it must be an instance method + if (Modifier.isStatic(meth.getModifiers())) { + return; + } + + // First check if this is a bean event addition method + int n = meth.getParameterTypes().length; + String methname = meth.getName(); + if ((methname.startsWith("add") || methname.startsWith("set")) + && methname.endsWith("Listener") && n == 1 && meth.getReturnType() == Void.TYPE + && EventListener.class.isAssignableFrom(meth.getParameterTypes()[0])) { + // Yes, we have discovered an event type. Save the information for later. + Class eventClass = meth.getParameterTypes()[0]; + String ename = eventClass.getName(); + int idot = ename.lastIndexOf('.'); + if (idot != -1) { + ename = ename.substring(idot + 1); } + ename = normalize(StringUtil.decapitalize(ename)); + events.put(ename, new PyBeanEvent<>(ename, eventClass, meth)); + return; + } - // Now check if it's a bean property accessor - String beanPropertyName = null; - boolean get = true; - if (methname.startsWith("get") && methname.length() > 3 && n == 0) { - beanPropertyName = methname.substring(3); - } else if (methname.startsWith("is") && methname.length() > 2 && n == 0 - && meth.getReturnType() == Boolean.TYPE) { - beanPropertyName = methname.substring(2); - } else if (methname.startsWith("set") && methname.length() > 3 && n == 1) { - beanPropertyName = methname.substring(3); - get = false; - } - if (beanPropertyName != null) { - beanPropertyName = normalize(StringUtil.decapitalize(beanPropertyName)); - PyBeanProperty prop = props.get(beanPropertyName); - if (prop == null) { - prop = new PyBeanProperty(beanPropertyName, null, null, null); - props.put(beanPropertyName, prop); - } - if (get) { - prop.getMethod = meth; - prop.myType = meth.getReturnType(); - } else { - prop.setMethod = meth; - // Needed for readonly properties. Getter will be used instead - // if there is one. Only works if setX method has exactly one - // param, which is the only reasonable case. - // XXX: should we issue a warning if setX and getX have different - // types? - if (prop.myType == null) { - Class[] params = meth.getParameterTypes(); - if (params.length == 1) { - prop.myType = params[0]; - } + // Now check if it's a bean property accessor + String beanPropertyName = null; + boolean get = true; + if (methname.startsWith("get") && methname.length() > 3 && n == 0) { + beanPropertyName = methname.substring(3); + } else if (methname.startsWith("is") && methname.length() > 2 && n == 0 + && meth.getReturnType() == Boolean.TYPE) { + beanPropertyName = methname.substring(2); + } else if (methname.startsWith("set") && methname.length() > 3 && n == 1) { + beanPropertyName = methname.substring(3); + get = false; + } + + if (beanPropertyName != null) { + // Ok, its a bean property. Save this information for later. + beanPropertyName = normalize(StringUtil.decapitalize(beanPropertyName)); + PyBeanProperty prop = props.get(beanPropertyName); + if (prop == null) { + prop = new PyBeanProperty(beanPropertyName, null, null, null); + props.put(beanPropertyName, prop); + } + // getX and setX should be getting and setting the same type of thing. + if (get) { + prop.getMethod = meth; + prop.myType = meth.getReturnType(); + } else { + prop.setMethod = meth; + /* + * Needed for readonly properties. Getter will be used instead if there is one. Only + * works if setX method has exactly one param, which is the only reasonable case. + */ + // XXX: should we issue a warning if setX and getX have different types? + if (prop.myType == null) { + Class[] params = meth.getParameterTypes(); + if (params.length == 1) { + prop.myType = params[0]; } } } } + } - // Add superclass methods + /** + * Add descriptors to this type's dictionary ({@code __dict__}) for methods inherited from + * ancestor classes. This is exclusively a helper method for {@link #init(Set)}. + *

    + * Python finds an inherited method by looking in the dictionaries of types along the MRO. This + * is does not directly emulate the signature polymorphism of Java. Even though the entries of + * the MRO include the {@code PyType}s of the Java ancestors of this class, each type's + * dictionary is keyed on the simple name of the method. For the present class, and at the point + * where this method is called, any method defined on this class has created a descriptor entry + * for that method name (see {@link #addMethods(Class, List, Map, Map, Method[])}), but only for + * the signatures defined directly in this class. If any method of the same simple name is + * inherited in Java from a super-class, it is now shadowed by this entry as far as Python is + * concerned. The purpose of this method is to add the shadowed method signatures. + *

    + * For example {@code AbstractCollection} defines {@code add(E)}, and {@code AbstractList} + * inherits it but also defines {@code add(int, E)} (giving control of the insertion point). + * When {@link #addMethods(Class, List, Map, Map, Method[])} completes, the "add" descriptor in + * {@code type(AbstractList)}, represents only {@code add(int, E)}, and we must add the + * inherited signature for {@code add(E)}. + * + * @param reflectedFuncs to which reflected functions are added for further processing + * @param methods of the target class + */ + private void addInheritedMethods(List reflectedFuncs, Method[] methods) { for (Method meth : methods) { String nmethname = normalize(meth.getName()); - PyReflectedFunction reflfunc = (PyReflectedFunction)dict.__finditem__(nmethname); + PyReflectedFunction reflfunc = (PyReflectedFunction) dict.__finditem__(nmethname); if (reflfunc != null) { - // The superclass method has the same name as one declared on this class, so add - // the superclass version's arguments + /* + * The superclass method has the same name as one declared on this class, so add the + * superclass version's arguments. + */ reflfunc.addMethod(meth); } else if (PyReflectedFunction.isPackagedProtected(meth.getDeclaringClass()) && lookup(nmethname) == null) { - // This method must be a public method from a package protected superclass. It's - // visible from Java on this class, so do the same for Python here. This is the - // flipside of what handleSuperMethodArgCollisions does for inherited public methods - // on package protected classes. - dict.__setitem__(nmethname, new PyReflectedFunction(meth)); + /* + * This method must be a public method from a package protected superclass. It's + * visible from Java on this class, so do the same for Python here. This is the + * flipside of what handleSuperMethodArgCollisions does for inherited public methods + * on package protected classes. + */ + reflfunc = new PyReflectedFunction(meth); + reflectedFuncs.add(reflfunc); + dict.__setitem__(nmethname, reflfunc); } } + } - // Add fields declared on this type - Field[] fields; - if (Options.respectJavaAccessibility) { - // returns just the public fields - fields = forClass.getFields(); - } else { - fields = forClass.getDeclaredFields(); - for (Field field : fields) { - field.setAccessible(true); - } - } + /** + * Process the given fields defined on the target class (the fromClass). + * + * This is exclusively a helper method for {@link #init(Set)}. + * + * + * @param baseClass + * @param fields + */ + private void addFields(Class baseClass, Field[] fields) { for (Field field : fields) { - if (!declaredOnMember(baseClass, field)) { + if (!declaredHere(baseClass, field)) { continue; } String fldname = field.getName(); if (Modifier.isStatic(field.getModifiers())) { if (fldname.startsWith("__doc__") && fldname.length() > 7 - && field.getType() == PyString.class) { + && CharSequence.class.isAssignableFrom(field.getType())) { String fname = fldname.substring(7).intern(); PyObject memb = dict.__finditem__(fname); if (memb != null && memb instanceof PyReflectedFunction) { - PyString doc = null; + CharSequence doc = null; try { - doc = (PyString)field.get(null); + doc = (CharSequence) field.get(null); } catch (IllegalAccessException e) { throw Py.JavaError(e); } - ((PyReflectedFunction)memb).__doc__ = doc; + ((PyReflectedFunction) memb).__doc__ = doc instanceof PyString + ? (PyString) doc : new PyString(doc.toString()); } } } @@ -441,8 +870,11 @@ && lookup(nmethname) == null) { dict.__setitem__(normalize(fldname), new PyReflectedField(field)); } } + } - for (PyBeanEvent ev : events.values()) { + /** Add the methods corresponding to a each discovered JavaBean event. */ + private void addBeanEvents(Map> events) { + for (PyBeanEvent ev : events.values()) { if (dict.__finditem__(ev.__name__) == null) { dict.__setitem__(ev.__name__, ev); } @@ -452,42 +884,51 @@ && lookup(nmethname) == null) { if (dict.__finditem__(methodName) != null) { continue; } - dict.__setitem__(methodName, new PyBeanEventProperty(methodName, - ev.eventClass, - ev.addMethod, - meth)); + dict.__setitem__(methodName, + new PyBeanEventProperty(methodName, ev.eventClass, ev.addMethod, meth)); } } + } - // Fill in the bean properties picked up while going through the methods + /** Add the methods corresponding to a each discovered JavaBean property. */ + private void addBeanProperties(Map props) { for (PyBeanProperty prop : props.values()) { + + // Check for an existing __dict__ entry with this name PyObject prev = dict.__finditem__(prop.__name__); if (prev != null) { if (!(prev instanceof PyReflectedField) - || !Modifier.isStatic(((PyReflectedField)prev).field.getModifiers())) { + || !Modifier.isStatic(((PyReflectedField) prev).field.getModifiers())) { // Any methods or non-static fields take precedence over the bean property continue; } else { // Must've been a static field, so add it to the property - prop.field = ((PyReflectedField)prev).field; + prop.field = ((PyReflectedField) prev).field; } } - // If one of our superclasses has something defined for this name, check if its a bean - // property, and if so, try to fill in any gaps in our property from there - PyObject fromType[] = new PyObject[] { null }; + /* + * If one of our super-classes has something defined for this name, check if it's a bean + * property, and if so, try to fill in any gaps in our property from there. + */ + PyObject fromType[] = new PyObject[] {null}; PyObject superForName = lookup_where_mro(prop.__name__, fromType); + if (superForName instanceof PyBeanProperty) { - PyBeanProperty superProp = ((PyBeanProperty)superForName); - // If it has a set method and we don't, take it regardless. If the types don't line - // up, it'll be rejected below + PyBeanProperty superProp = ((PyBeanProperty) superForName); + /* + * If it has a set method and we don't, take it regardless. If the types don't line + * up, it'll be rejected below. + */ if (prop.setMethod == null) { prop.setMethod = superProp.setMethod; } else if (prop.getMethod == null - && superProp.myType == prop.setMethod.getParameterTypes()[0]) { - // Only take a get method if the type on it agrees with the set method - // we already have. The bean on this type overrides a conflicting one - // of the parent + && superProp.myType == prop.setMethod.getParameterTypes()[0]) { + /* + * Only take a get method if the type on it agrees with the set method we + * already have. The bean on this type overrides a conflicting one of the + * parent. + */ prop.getMethod = superProp.getMethod; prop.myType = superProp.myType; } @@ -496,44 +937,50 @@ && lookup(nmethname) == null) { // If the parent bean is hiding a static field, we need it as well. prop.field = superProp.field; } - } else if (superForName != null && fromType[0] != this && !(superForName instanceof PyBeanEvent)) { - // There is already an entry for this name - // It came from a type which is not @this; it came from a superclass - // It is not a bean event - // Do not override methods defined in superclass + + } else if (superForName != null && fromType[0] != this + && !(superForName instanceof PyBeanEvent)) { + /* + * There is already an entry for this name. It came from a type which is not @this; + * it came from a superclass. It is not a bean event. Do not override methods + * defined in superclass. + */ continue; } - // If the return types on the set and get methods for a property don't agree, the get - // method takes precedence + + /* + * If the return types on the set and get methods for a property don't agree, the get + * method takes precedence. + */ if (prop.getMethod != null && prop.setMethod != null && prop.myType != prop.setMethod.getParameterTypes()[0]) { prop.setMethod = null; } dict.__setitem__(prop.__name__, prop); } + } + + /** + * Process the given constructors defined on the target class (the fromClass). + * + * This is exclusively a helper method for {@link #init(Set)}. + * + * @param forClass + * @param constructors + */ + private void addConstructors(Class forClass, Constructor[] constructors) { final PyReflectedConstructor reflctr = new PyReflectedConstructor(name); - Constructor[] constructors; - // No matter the security manager, trying to set the constructor on class to accessible - // blows up - if (Options.respectJavaAccessibility || Class.class == forClass) { - // returns just the public constructors - constructors = forClass.getConstructors(); - } else { - constructors = forClass.getDeclaredConstructors(); - for (Constructor ctr : constructors) { - ctr.setAccessible(true); - } - } for (Constructor ctr : constructors) { reflctr.addConstructor(ctr); } + if (PyObject.class.isAssignableFrom(forClass)) { PyObject new_ = new PyNewWrapper(forClass, "__new__", -1, -1) { - @Override public PyObject new_impl(boolean init, - PyType subtype, - PyObject[] args, - String[] keywords) { + + @Override + public PyObject new_impl(boolean init, PyType subtype, PyObject[] args, + String[] keywords) { return reflctr.make(args, keywords); } }; @@ -541,13 +988,23 @@ && lookup(nmethname) == null) { } else { dict.__setitem__("__init__", reflctr); } + } + + /** + * Add Python methods corresponding to the API of common Java collection types. This is + * exclusively a helper method for {@link #init(Set)}. + * + * @param forClass the target class + */ + private void addCollectionProxies(Class forClass) { PyBuiltinMethod[] collectionProxyMethods = getCollectionProxies().get(forClass); if (collectionProxyMethods != null) { for (PyBuiltinMethod meth : collectionProxyMethods) { addMethod(meth); } } - // allow for some methods to override the Java type's methods as a late injection + + // Allow for some methods to override the Java type's methods as a late injection for (Class type : getPostCollectionProxies().keySet()) { if (type.isAssignableFrom(forClass)) { for (PyBuiltinMethod meth : getPostCollectionProxies().get(type)) { @@ -555,166 +1012,154 @@ && lookup(nmethname) == null) { } } } + } - if (ClassDictInit.class.isAssignableFrom(forClass) && forClass != ClassDictInit.class) { - try { - Method m = forClass.getMethod("classDictInit", PyObject.class); - m.invoke(null, dict); - // allow the class to override its name after it is loaded - PyObject nameSpecified = dict.__finditem__("__name__"); - if (nameSpecified != null) { - name = nameSpecified.toString(); - } - } catch (Exception exc) { - throw Py.JavaError(exc); + /** Add special methods when this PyJavaType represents Object. */ + private void addMethodsForObject() { + addMethod(new PyBuiltinMethodNarrow("__copy__") { + + @Override + public PyObject __call__() { + throw Py.TypeError( + "Could not copy Java object because it is not Cloneable or known to be immutable. " + + "Consider monkeypatching __copy__ for " + + self.getType().fastGetName()); } - } + }); + addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { - if (baseClass != Object.class) { - hasGet = getDescrMethod(forClass, "__get__", OO) != null - || getDescrMethod(forClass, "_doget", PyObject.class) != null - || getDescrMethod(forClass, "_doget", OO) != null; - hasSet = getDescrMethod(forClass, "__set__", OO) != null - || getDescrMethod(forClass, "_doset", OO) != null; - hasDelete = getDescrMethod(forClass, "__delete__", PyObject.class) != null - || getDescrMethod(forClass, "_dodel", PyObject.class) != null; - } + @Override + public PyObject __call__(PyObject memo) { + throw Py.TypeError("Could not deepcopy Java object because it is not Serializable. " + + "Consider monkeypatching __deepcopy__ for " + + self.getType().fastGetName()); + } + }); + addMethod(new PyBuiltinMethodNarrow("__eq__", 1) { - if (forClass == Object.class) { - addMethod(new PyBuiltinMethodNarrow("__copy__") { - @Override - public PyObject __call__() { - throw Py.TypeError("Could not copy Java object because it is not Cloneable or known to be immutable. " - + "Consider monkeypatching __copy__ for " + self.getType().fastGetName()); - } - }); - addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { - @Override - public PyObject __call__(PyObject memo) { - throw Py.TypeError("Could not deepcopy Java object because it is not Serializable. " - + "Consider monkeypatching __deepcopy__ for " + self.getType().fastGetName()); - } - }); - addMethod(new PyBuiltinMethodNarrow("__eq__", 1) { - @Override - public PyObject __call__(PyObject o) { - Object proxy = self.getJavaProxy(); - Object oProxy = o.getJavaProxy(); - return proxy.equals(oProxy) ? Py.True : Py.False; - } - }); - addMethod(new PyBuiltinMethodNarrow("__ne__", 1) { - @Override - public PyObject __call__(PyObject o) { - Object proxy = self.getJavaProxy(); - Object oProxy = o.getJavaProxy(); - return !proxy.equals(oProxy) ? Py.True : Py.False; - } - }); - addMethod(new PyBuiltinMethodNarrow("__hash__") { - @Override - public PyObject __call__() { - return Py.newInteger(self.getJavaProxy().hashCode()); - } - }); - addMethod(new PyBuiltinMethodNarrow("__repr__") { - @Override - public PyObject __call__() { - /* - * java.lang.Object.toString returns Unicode: preserve as a PyUnicode, then let - * the repr() built-in decide how to handle it. (Also applies to __str__.) - */ - String toString = self.getJavaProxy().toString(); - return toString == null ? Py.EmptyUnicode : Py.newUnicode(toString); - } - }); - addMethod(new PyBuiltinMethodNarrow("__unicode__") { - @Override - public PyObject __call__() { - return new PyUnicode(self.toString()); - } - }); - } + @Override + public PyObject __call__(PyObject o) { + Object proxy = self.getJavaProxy(); + Object oProxy = o.getJavaProxy(); + return proxy.equals(oProxy) ? Py.True : Py.False; + } + }); + addMethod(new PyBuiltinMethodNarrow("__ne__", 1) { - if(forClass == Comparable.class) { - addMethod(new ComparableMethod("__lt__", 1) { - @Override - protected boolean getResult(int comparison) { - return comparison < 0; - } - }); - addMethod(new ComparableMethod("__le__", 1) { - @Override - protected boolean getResult(int comparison) { - return comparison <= 0; - } - }); - addMethod(new ComparableMethod("__gt__", 1) { - @Override - protected boolean getResult(int comparison) { - return comparison > 0; - } - }); - addMethod(new ComparableMethod("__ge__", 1) { - @Override - protected boolean getResult(int comparison) { - return comparison >= 0; - } - }); - } + @Override + public PyObject __call__(PyObject o) { + Object proxy = self.getJavaProxy(); + Object oProxy = o.getJavaProxy(); + return !proxy.equals(oProxy) ? Py.True : Py.False; + } + }); + addMethod(new PyBuiltinMethodNarrow("__hash__") { - if (immutableClasses.contains(forClass)) { - // __deepcopy__ just works for these objects since it uses serialization instead - addMethod(new PyBuiltinMethodNarrow("__copy__") { - @Override - public PyObject __call__() { - return self; - } - }); - } + @Override + public PyObject __call__() { + return Py.newInteger(self.getJavaProxy().hashCode()); + } + }); + addMethod(new PyBuiltinMethodNarrow("__repr__") { - if(forClass == Cloneable.class) { - addMethod(new PyBuiltinMethodNarrow("__copy__") { - @Override - public PyObject __call__() { - Object obj = self.getJavaProxy(); - Method clone; - // TODO we could specialize so that for well known objects like collections. - // This would avoid needing to use reflection in the general case, - // because Object#clone is protected (but most subclasses are not). - // - // Lastly we can potentially cache the method handle in the proxy instead of looking it up each time - try { - clone = obj.getClass().getMethod("clone"); - Object copy = clone.invoke(obj); - return Py.java2py(copy); - } catch (Exception ex) { - throw Py.TypeError("Could not copy Java object"); - } + @Override + public PyObject __call__() { + /* + * java.lang.Object.toString returns Unicode: preserve as a PyUnicode, then let the + * repr() built-in decide how to handle it. (Also applies to __str__.) + */ + String toString = self.getJavaProxy().toString(); + return toString == null ? Py.EmptyUnicode : Py.newUnicode(toString); + } + }); + addMethod(new PyBuiltinMethodNarrow("__unicode__") { + + @Override + public PyObject __call__() { + return new PyUnicode(self.toString()); + } + }); + } + + /** Add special methods when this PyJavaType represents interface Comparable. */ + private void addMethodsForComparable() { + addMethod(new ComparableMethod("__lt__", 1) { + + @Override + protected boolean getResult(int comparison) { + return comparison < 0; + } + }); + addMethod(new ComparableMethod("__le__", 1) { + + @Override + protected boolean getResult(int comparison) { + return comparison <= 0; + } + }); + addMethod(new ComparableMethod("__gt__", 1) { + + @Override + protected boolean getResult(int comparison) { + return comparison > 0; + } + }); + addMethod(new ComparableMethod("__ge__", 1) { + + @Override + protected boolean getResult(int comparison) { + return comparison >= 0; + } + }); + } + + /** Add special methods when this PyJavaType represents interface Cloneable. */ + private void addMethodsForCloneable() { + addMethod(new PyBuiltinMethodNarrow("__copy__") { + + @Override + public PyObject __call__() { + Object obj = self.getJavaProxy(); + Method clone; + /* + * TODO we could specialize so that for well known objects like collections. This + * would avoid needing to use reflection in the general case, because Object#clone + * is protected (but most subclasses are not). Lastly we can potentially cache the + * method handle in the proxy instead of looking it up each time + */ + try { + clone = obj.getClass().getMethod("clone"); + Object copy = clone.invoke(obj); + return Py.java2py(copy); + } catch (Exception ex) { + throw Py.TypeError("Could not copy Java object"); } - }); - } + } + }); + } - if(forClass == Serializable.class) { - addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { - @Override - public PyObject __call__(PyObject memo) { - Object obj = self.getJavaProxy(); - try { - Object copy = cloneX(obj); - return Py.java2py(copy); - } catch (Exception ex) { - throw Py.TypeError("Could not copy Java object"); - } + /** Add special methods when this PyJavaType represents interface Serializable. */ + private void addMethodsForSerializable() { + addMethod(new PyBuiltinMethodNarrow("__deepcopy__") { + + @Override + public PyObject __call__(PyObject memo) { + Object obj = self.getJavaProxy(); + try { + Object copy = cloneX(obj); + return Py.java2py(copy); + } catch (Exception ex) { + throw Py.TypeError("Could not copy Java object"); } - }); - } + } + }); } - // cloneX, CloneOutput, CloneInput are verbatim from Eamonn McManus' - // http://weblogs.java.net/blog/emcmanus/archive/2007/04/cloning_java_ob.html - // blog post on deep cloning through serialization - - // just what we need for __deepcopy__ support of Java objects + /* + * cloneX, CloneOutput, CloneInput are verbatim from Eamonn McManus' + * http://weblogs.java.net/blog/emcmanus/archive/2007/04/cloning_java_ob.html blog post on deep + * cloning through serialization - just what we need for __deepcopy__ support of Java objects + */ private static T cloneX(T x) throws IOException, ClassNotFoundException { ByteArrayOutputStream bout = new ByteArrayOutputStream(); CloneOutput cout = new CloneOutput(bout); @@ -726,10 +1171,12 @@ private static T cloneX(T x) throws IOException, ClassNotFoundException { @SuppressWarnings("unchecked") // thanks to Bas de Bakker for the tip! T clone = (T) cin.readObject(); + cin.close(); return clone; } private static class CloneOutput extends ObjectOutputStream { + Queue> classQueue = new LinkedList>(); CloneOutput(OutputStream out) throws IOException { @@ -748,6 +1195,7 @@ protected void annotateProxyClass(Class c) { } private static class CloneInput extends ObjectInputStream { + private final CloneOutput output; CloneInput(InputStream in, CloneOutput output) throws IOException { @@ -762,8 +1210,8 @@ protected Class resolveClass(ObjectStreamClass osc) String expected = osc.getName(); String found = (c == null) ? null : c.getName(); if (!expected.equals(found)) { - throw new InvalidClassException("Classes desynchronized: " + - "found " + found + " when expecting " + expected); + throw new InvalidClassException("Classes desynchronized: " + "found " + found + + " when expecting " + expected); } return c; } @@ -776,34 +1224,51 @@ protected Class resolveProxyClass(String[] interfaceNames) } /** - * Private, protected or package protected classes that implement public interfaces or extend - * public classes can't have their implementations of the methods of their supertypes called - * through reflection due to Sun VM bug 4071957(http://tinyurl.com/le9vo). They can be called - * through the supertype version of the method though. Unfortunately we can't just let normal - * mro lookup of those methods handle routing the call to the correct version as a class can - * implement interfaces or classes that each have methods with the same name that takes - * different number or types of arguments. Instead this method goes through all interfaces - * implemented by this class, and combines same-named methods into a single PyReflectedFunction. + * Methods implemented in private, protected or package protected classes, and classes not + * exported by their module, may not be called directly through reflection. This is discussed in + * JDK issue 4283544, + * and is not likely to change. They may however be called through the Method object of the + * accessible class or interface that they implement. In non-reflective code, the Java compiler + * would generate such a call, based on the type declared for the target, which must + * therefore be accessible. + *

    + * An MRO lookup on the actual class will find a PyReflectedFunction that defines + * the method to Python. The normal process for creating that object will add the + * inaccessible implementation method(s) to the list, not those of the public API. (A + * class can of course have several methods with the same name and different signatures and the + * PyReflectedFunction lists them all.) We must therefore take care to enter the + * corresponding accessible API methods instead. + *

    + * Prior to Jython 2.5, this was handled by setting methods in package protected classes + * accessible which made them callable through reflection. That had the drawback of failing when + * running in a security environment that didn't allow setting accessibility, and will fail on + * the modular Java platform, so this method replaced it. * - * Prior to Jython 2.5, this was handled in PyJavaClass.setMethods by setting methods in package - * protected classes accessible which made them callable through reflection. That had the - * drawback of failing when running in a security environment that didn't allow setting - * accessibility, so this method replaced it. + * @param forClass of which the methods are currently being defined */ private void handleSuperMethodArgCollisions(Class forClass) { for (Class iface : forClass.getInterfaces()) { mergeMethods(iface); } - if (forClass.getSuperclass() != null) { - mergeMethods(forClass.getSuperclass()); - if (!Modifier.isPublic(forClass.getSuperclass().getModifiers())) { - // If the superclass is also not public, it needs to get the same treatment as we - // can't call its methods either. - handleSuperMethodArgCollisions(forClass.getSuperclass()); + Class parent = forClass.getSuperclass(); + if (parent != null) { + if (isAccessibleClass(parent)) { + mergeMethods(parent); + } else { + // The parent class is also not public: go up one more in the ancestry. + handleSuperMethodArgCollisions(parent); } } } + /** + * From a given class that is an ancestor of the Java class for which this PyJavaType is being + * initialised, or that is an interface implemented by it or an ancestor, process each method in + * the ancestor so that, if the class or interface that declares the method is public, that + * method becomes a method of the Python type we are constructing. + * + * @param parent class or interface + */ private void mergeMethods(Class parent) { for (Method meth : parent.getMethods()) { if (!Modifier.isPublic(meth.getDeclaringClass().getModifiers())) { @@ -814,29 +1279,49 @@ private void mergeMethods(Class parent) { PyObject[] where = new PyObject[1]; PyObject obj = lookup_where_mro(nmethname, where); if (obj == null) { - // Nothing in our supertype hierarchy defines something with this name, so it - // must not be visible there. + /* + * Nothing in our supertype hierarchy defines something with this name, so it must + * not be visible there. + */ continue; } else if (where[0] == this) { - // This method is the only thing defining items in this class' dict, so it must - // be a PyReflectedFunction created here. See if it needs the current method - // added to it. - if (!((PyReflectedFunction)obj).handles(meth)) { - ((PyReflectedFunction)obj).addMethod(meth); + /* + * This method is the only thing defining items in this class' dict, so it must be a + * PyReflectedFunction created here. See if it needs the current method added to it. + */ + if (!((PyReflectedFunction) obj).handles(meth)) { + ((PyReflectedFunction) obj).addMethod(meth); } } else { - // There's something in a superclass with the same name. Add an item to this type's - // dict to hide it. If it's this method, nothing's changed. If it's a field, we - // want to make the method visible. If it's a different method, it'll be added to - // the reflected function created here in a later call. + /* + * There's something in a superclass with the same name. Add an item to this type's + * dict to hide it. If it's this method, nothing's changed. If it's a field, we want + * to make the method visible. If it's a different method, it'll be added to the + * reflected function created here in a later call. + */ dict.__setitem__(nmethname, new PyReflectedFunction(meth)); } } } - private static boolean declaredOnMember(Class base, Member declaring) { - return base == null || (declaring.getDeclaringClass() != base && - base.isAssignableFrom(declaring.getDeclaringClass())); + /** + * True iff the target of this PyJavaType's target (the forClass) + * declares the given member of this target. For this, the method is supplied the super-class of + * the target. + * + * @param baseClass super-class of the target of this PyJavaType, or + * null. + * @param member of the forClass that might be exposed on this + * PyJavaType + * @return true if the member is declared here on the fromClass + */ + private static boolean declaredHere(Class baseClass, Member member) { + if (baseClass == null) { + return true; + } else { + Class declaring = member.getDeclaringClass(); + return declaring != baseClass && baseClass.isAssignableFrom(declaring); + } } private static String normalize(String name) { @@ -859,6 +1344,7 @@ private static Method getDescrMethod(Class c, String name, Class... parmty return null; } + /** Recognise certain methods as ignored (tagged as throws PyIgnoreMethodTag). */ private static boolean ignore(Method meth) { Class[] exceptions = meth.getExceptionTypes(); for (Class exception : exceptions) { @@ -870,12 +1356,14 @@ private static boolean ignore(Method meth) { } private static class EnumerationIter extends PyIterator { + private Enumeration proxy; public EnumerationIter(Enumeration proxy) { this.proxy = proxy; } + @Override public PyObject __iternext__() { return proxy.hasMoreElements() ? Py.java2py(proxy.nextElement()) : null; } @@ -887,13 +1375,14 @@ protected ComparableMethod(String name, int numArgs) { super(name, numArgs); } + @SuppressWarnings("unchecked") @Override public PyObject __call__(PyObject arg) { Object asjava = arg.__tojava__(Object.class); int compare; try { - compare = ((Comparable)self.getJavaProxy()).compareTo(asjava); - } catch(ClassCastException classCast) { + compare = ((Comparable) self.getJavaProxy()).compareTo(asjava); + } catch (ClassCastException classCast) { return Py.NotImplemented; } return getResult(compare) ? Py.True : Py.False; @@ -902,10 +1391,12 @@ public PyObject __call__(PyObject arg) { protected abstract boolean getResult(int comparison); } - // Traverseproc-note: Usually we would have to traverse this class, but we can - // leave this out, since CollectionProxies is only used locally in private - // static fields. + /* + * Traverseproc-note: Usually we would have to traverse this class, but we can leave this out, + * since CollectionProxies is only used locally in private static fields. + */ private static class CollectionProxies { + final Map, PyBuiltinMethod[]> proxies; final Map, PyBuiltinMethod[]> postProxies; @@ -916,6 +1407,7 @@ private static class CollectionProxies { } private static class CollectionsProxiesHolder { + static final CollectionProxies proxies = new CollectionProxies(); } @@ -938,20 +1430,24 @@ private static Map, PyBuiltinMethod[]> buildCollectionProxies() { final Map, PyBuiltinMethod[]> proxies = new HashMap<>(); PyBuiltinMethodNarrow iterableProxy = new PyBuiltinMethodNarrow("__iter__") { + + @SuppressWarnings("unchecked") @Override public PyObject __call__() { - return new JavaIterator(((Iterable) self.getJavaProxy())); + return new JavaIterator(((Iterable) self.getJavaProxy())); } }; - proxies.put(Iterable.class, new PyBuiltinMethod[]{iterableProxy}); + proxies.put(Iterable.class, new PyBuiltinMethod[] {iterableProxy}); PyBuiltinMethodNarrow lenProxy = new PyBuiltinMethodNarrow("__len__") { + @Override public PyObject __call__() { return Py.newInteger(((Collection) self.getJavaProxy()).size()); } }; PyBuiltinMethodNarrow containsProxy = new PyBuiltinMethodNarrow("__contains__", 1) { + @Override public PyObject __call__(PyObject obj) { boolean contained = false; @@ -971,23 +1467,27 @@ public PyObject __call__(PyObject obj) { return contained ? Py.True : Py.False; } }; - proxies.put(Collection.class, new PyBuiltinMethod[]{lenProxy, containsProxy}); + proxies.put(Collection.class, new PyBuiltinMethod[] {lenProxy, containsProxy}); PyBuiltinMethodNarrow iteratorProxy = new PyBuiltinMethodNarrow("__iter__") { + + @SuppressWarnings("unchecked") @Override public PyObject __call__() { - return new JavaIterator(((Iterator) self.getJavaProxy())); + return new JavaIterator(((Iterator) self.getJavaProxy())); } }; - proxies.put(Iterator.class, new PyBuiltinMethod[]{iteratorProxy}); + proxies.put(Iterator.class, new PyBuiltinMethod[] {iteratorProxy}); PyBuiltinMethodNarrow enumerationProxy = new PyBuiltinMethodNarrow("__iter__") { + + @SuppressWarnings("unchecked") @Override public PyObject __call__() { - return new EnumerationIter(((Enumeration) self.getJavaProxy())); + return new EnumerationIter(((Enumeration) self.getJavaProxy())); } }; - proxies.put(Enumeration.class, new PyBuiltinMethod[]{enumerationProxy}); + proxies.put(Enumeration.class, new PyBuiltinMethod[] {enumerationProxy}); proxies.put(List.class, JavaProxyList.getProxyMethods()); proxies.put(Map.class, JavaProxyMap.getProxyMethods()); proxies.put(Set.class, JavaProxySet.getProxyMethods()); @@ -1002,8 +1502,9 @@ private static Map, PyBuiltinMethod[]> buildPostCollectionProxies() { return Collections.unmodifiableMap(postProxies); } - private class ClassComparator implements Comparator> { + private class ClassComparator implements Comparator> { + @Override public int compare(Class c1, Class c2) { if (c1.equals(c2)) { return 0; @@ -1026,7 +1527,7 @@ private String hierarchyName(Class c) { c = c.getSuperclass(); } while (c != null); - for (String name: nameStack) { + for (String name : nameStack) { namesBuilder.append(name); } @@ -1042,6 +1543,7 @@ public MethodComparator(ClassComparator classComparator) { this.classComparator = classComparator; } + @Override public int compare(Method m1, Method m2) { int result = m1.getName().compareTo(m2.getName()); @@ -1084,7 +1586,7 @@ public int traverse(Visitproc visit, Object arg) { return retVal; } if (conflicted != null) { - for (PyObject ob: conflicted) { + for (PyObject ob : conflicted) { if (ob != null) { retVal = visit.visit(ob, arg); if (retVal != 0) { @@ -1102,7 +1604,7 @@ public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationExceptio return false; } if (conflicted != null) { - for (PyObject obj: conflicted) { + for (PyObject obj : conflicted) { if (obj == ob) { return true; } diff --git a/src/org/python/core/PyList.java b/src/org/python/core/PyList.java index f952e5398..89f0bf727 100644 --- a/src/org/python/core/PyList.java +++ b/src/org/python/core/PyList.java @@ -43,10 +43,10 @@ public PyList(PyType type) { list = Generic.list(); } - private PyList(List list, boolean convert) { + private PyList(List list, boolean convert) { super(TYPE); if (!convert) { - this.list = list; + this.list = (List) list; } else { this.list = Generic.list(); for (Object o : list) { @@ -72,7 +72,7 @@ public PyList(PyObject[] elements) { this(TYPE, elements); } - public PyList(Collection c) { + public PyList(Collection c) { this(TYPE, c); } @@ -106,7 +106,7 @@ public PyList(Iterator iter) { // refactor and put in Py presumably; // presumably we can consume an arbitrary iterable too! private static void addCollection(List list, Collection seq) { - Map seen = new HashMap(); + Map seen = new HashMap<>(); for (Object item : seq) { long id = Py.java_obj_id(item); PyObject seen_obj = seen.get(id); @@ -118,6 +118,7 @@ private static void addCollection(List list, Collection seq) { } } + @SuppressWarnings("unchecked") @ExposedNew @ExposedMethod(doc = BuiltinDocs.list___init___doc) final void list___init__(PyObject[] args, String[] kwds) { @@ -141,7 +142,7 @@ final void list___init__(PyObject[] args, String[] kwds) { list.addAll(((PyTuple) seq).getList()); } else if (seq.getClass().isAssignableFrom(Collection.class)) { System.err.println("Adding from collection"); - addCollection(list, (Collection)seq); + addCollection(list, (Collection) seq); } else { for (PyObject item : seq.asIterable()) { append(item); @@ -169,6 +170,7 @@ protected void delRange(int start, int stop) { remove(start, stop); } + @SuppressWarnings("unchecked") @Override protected void setslice(int start, int stop, int step, PyObject value) { if (stop < start) { @@ -182,11 +184,11 @@ protected void setslice(int start, int stop, int step, PyObject value) { } else if (value instanceof PySequence) { setsliceIterator(start, stop, step, value.asIterable().iterator()); } else if (value instanceof List) { - setsliceList(start, stop, step, (List)value); + setsliceList(start, stop, step, (List)value); } else { Object valueList = value.__tojava__(List.class); if (valueList != null && valueList != Py.NoConversion) { - setsliceList(start, stop, step, (List)valueList); + setsliceList(start, stop, step, (List)valueList); } else { value = new PyList(value); setsliceIterator(start, stop, step, value.asIterable().iterator()); @@ -194,7 +196,7 @@ protected void setslice(int start, int stop, int step, PyObject value) { } } - final private void setsliceList(int start, int stop, int step, List value) { + final private void setsliceList(int start, int stop, int step, List value) { if (step == 1) { list.subList(start, stop).clear(); int n = value.size(); @@ -333,7 +335,7 @@ final synchronized PyObject list___imul__(PyObject o) { int newSize = size * count; if (list instanceof ArrayList) { - ((ArrayList) list).ensureCapacity(newSize); + ((ArrayList) list).ensureCapacity(newSize); } List oldList = new ArrayList(list); for (int i = 1; i < count; i++) { @@ -379,8 +381,8 @@ final synchronized PyObject list___add__(PyObject o) { PyList sum = null; if (o instanceof PySequenceList && !(o instanceof PyTuple)) { if (o instanceof PyList) { - List oList = ((PyList) o).list; - List newList = new ArrayList(list.size() + oList.size()); + List oList = ((PyList) o).list; + ArrayList newList = new ArrayList<>(list.size() + oList.size()); newList.addAll(list); newList.addAll(oList); sum = fromList(newList); @@ -389,11 +391,12 @@ final synchronized PyObject list___add__(PyObject o) { // also support adding java lists (but not PyTuple!) Object oList = o.__tojava__(List.class); if (oList != Py.NoConversion && oList != null) { - List otherList = (List) oList; + @SuppressWarnings("unchecked") + List otherList = (List) oList; sum = new PyList(); sum.list_extend(this); - for (Iterator i = otherList.iterator(); i.hasNext();) { - sum.add(i.next()); + for (Object ob: otherList) { + sum.add(ob); } } } @@ -406,6 +409,7 @@ public PyObject __radd__(PyObject o) { } //XXX: needs __doc__ + @SuppressWarnings("unchecked") @ExposedMethod(type = MethodType.BINARY) final synchronized PyObject list___radd__(PyObject o) { // Support adding java.util.List, but prevent adding PyTuple. @@ -417,7 +421,7 @@ final synchronized PyObject list___radd__(PyObject o) { Object oList = o.__tojava__(List.class); if (oList != Py.NoConversion && oList != null) { sum = new PyList(); - sum.addAll((List) oList); + sum.addAll((List) oList); sum.extend(this); } return sum; @@ -798,7 +802,11 @@ private synchronized void sort(boolean reverse) { if (reverse) { Collections.reverse(list); // maintain stability of sort by reversing first } - Collections.sort(list, new PyObjectDefaultComparator(this)); + final PyObjectDefaultComparator comparator = new PyObjectDefaultComparator(this); + Collections.sort(list, comparator); + if (comparator.raisedException()) { + throw comparator.getRaisedException(); + } if (reverse) { Collections.reverse(list); // maintain stability of sort by reversing first } @@ -808,20 +816,33 @@ private synchronized void sort(boolean reverse) { private static class PyObjectDefaultComparator implements Comparator { private final PyList list; + private PyException comparatorException; PyObjectDefaultComparator(PyList list) { this.list = list; } + public PyException getRaisedException() { + return comparatorException; + } + + public boolean raisedException() { + return comparatorException != null; + } + + @Override public int compare(PyObject o1, PyObject o2) { // PEP 207 specifies that sort should only depend on "less-than" (Issue #1767) - int result; - if (o1._lt(o2).__nonzero__()) { - result = -1; - } else if (o2._lt(o1).__nonzero__()) { - result = 1; - } else { - result = 0; + int result = 0; // If exception is raised return objects are equal + try { + if (o1._lt(o2).__nonzero__()) { + result = -1; + } else if (o2._lt(o1).__nonzero__()) { + result = 1; + } + } catch (PyException pye) { + // #2399 Stash the exception so we can rethrow it later, and allow the sort to continue + comparatorException = pye; } if (this.list.gListAllocatedStatus >= 0) { throw Py.ValueError("list modified during sort"); @@ -829,6 +850,7 @@ public int compare(PyObject o1, PyObject o2) { return result; } + @Override public boolean equals(Object o) { if (o == this) { return true; @@ -849,8 +871,11 @@ private synchronized void sort(PyObject compare, boolean reverse) { if (reverse) { Collections.reverse(list); // maintain stability of sort by reversing first } - PyObjectComparator c = new PyObjectComparator(this, compare); - Collections.sort(list, c); + final PyObjectComparator comparator = new PyObjectComparator(this, compare); + Collections.sort(list, comparator); + if (comparator.raisedException()) { + throw comparator.getRaisedException(); + } if (reverse) { Collections.reverse(list); } @@ -861,20 +886,37 @@ private static class PyObjectComparator implements Comparator { private final PyList list; private final PyObject cmp; + private PyException comparatorException; PyObjectComparator(PyList list, PyObject cmp) { this.list = list; this.cmp = cmp; } + public PyException getRaisedException() { + return comparatorException; + } + + public boolean raisedException() { + return comparatorException != null; + } + + @Override public int compare(PyObject o1, PyObject o2) { - int result = cmp.__call__(o1, o2).asInt(); + int result = 0; // If exception is raised return objects are equal + try { + result = cmp.__call__(o1, o2).asInt(); + } catch (PyException pye) { + // #2399 Stash the exception so we can rethrow it later, and allow the sort to continue + comparatorException = pye; + } if (this.list.gListAllocatedStatus >= 0) { throw Py.ValueError("list modified during sort"); } return result; } + @Override public boolean equals(Object o) { if (o == this) { return true; @@ -958,7 +1000,7 @@ private synchronized void sort(PyObject cmp, PyObject key, boolean reverse) { Collections.reverse(decorated); } if (list instanceof ArrayList) { - ((ArrayList) list).ensureCapacity(size); + ((ArrayList) list).ensureCapacity(size); } for (KV kv : decorated) { list.add(kv.value); @@ -1063,8 +1105,8 @@ public synchronized boolean isEmpty() { } @Override - public Iterator iterator() { - return new Iterator() { + public Iterator iterator() { + return new Iterator() { private final Iterator iter = list.iterator(); diff --git a/src/org/python/core/PyListDerived.java b/src/org/python/core/PyListDerived.java index f4b159406..b378429cb 100644 --- a/src/org/python/core/PyListDerived.java +++ b/src/org/python/core/PyListDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyLong.java b/src/org/python/core/PyLong.java index 0c3378469..8b403ec93 100644 --- a/src/org/python/core/PyLong.java +++ b/src/org/python/core/PyLong.java @@ -295,17 +295,20 @@ public long asLong() { @Override public Object __tojava__(Class c) { try { + if (c == Boolean.TYPE || c == Boolean.class) { + return Boolean.valueOf(!getValue().equals(BigInteger.ZERO)); + } if (c == Byte.TYPE || c == Byte.class) { - return new Byte((byte)getLong(Byte.MIN_VALUE, Byte.MAX_VALUE)); + return Byte.valueOf((byte)getLong(Byte.MIN_VALUE, Byte.MAX_VALUE)); } if (c == Short.TYPE || c == Short.class) { - return new Short((short)getLong(Short.MIN_VALUE, Short.MAX_VALUE)); + return Short.valueOf((short)getLong(Short.MIN_VALUE, Short.MAX_VALUE)); } if (c == Integer.TYPE || c == Integer.class) { - return new Integer((int)getLong(Integer.MIN_VALUE, Integer.MAX_VALUE)); + return Integer.valueOf((int)getLong(Integer.MIN_VALUE, Integer.MAX_VALUE)); } if (c == Long.TYPE || c == Long.class) { - return new Long(getLong(Long.MIN_VALUE, Long.MAX_VALUE)); + return Long.valueOf(getLong(Long.MIN_VALUE, Long.MAX_VALUE)); } if (c == Float.TYPE || c == Double.TYPE || c == Float.class || c == Double.class) { return __float__().__tojava__(c); diff --git a/src/org/python/core/PyLongDerived.java b/src/org/python/core/PyLongDerived.java index d47dba46d..f22115f05 100644 --- a/src/org/python/core/PyLongDerived.java +++ b/src/org/python/core/PyLongDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyMemoryView.java b/src/org/python/core/PyMemoryView.java index 0fa1aeae6..8a653cc9f 100644 --- a/src/org/python/core/PyMemoryView.java +++ b/src/org/python/core/PyMemoryView.java @@ -43,8 +43,9 @@ public class PyMemoryView extends PySequence implements BufferProtocol, Traverse * new lease on it. The buffer so obtained will be writable if the underlying object permits it. * * @param pybuf buffer exported by some underlying object + * @throws ClassCastException in cases where {@code pybuf.getBuffer} does so. */ - public PyMemoryView(BufferProtocol pybuf) { + public PyMemoryView(BufferProtocol pybuf) throws ClassCastException { super(TYPE); /* * Ask for the full set of facilities (strides, indirect, etc.) from the object in case they @@ -68,11 +69,13 @@ static PyObject memoryview_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject obj = ap.getPyObject(0); if (obj instanceof BufferProtocol) { - return new PyMemoryView((BufferProtocol)obj); - } else { - throw Py.TypeError("cannot make memory view because object does not have " - + "the buffer interface"); + // Certain types that implement BufferProtocol do not implement the buffer protocol + try { + return new PyMemoryView((BufferProtocol) obj); + } catch (ClassCastException e) { /* fall through to message */ } } + throw Py.TypeError( + "cannot make memory view because object does not have the buffer interface"); } // @ExposedGet(doc = obj_doc) // Not exposed in Python 2.7 @@ -733,7 +736,7 @@ protected synchronized PyMemoryView getslice(int start, int stop, int step) { * * @param count the number of times to repeat this. * @return never - * @throws PyException(NotImlemented) always + * @throws PyException {@code NotImplemented} always */ @Override protected synchronized PyMemoryView repeat(int count) throws PyException { @@ -751,8 +754,8 @@ protected synchronized PyMemoryView repeat(int count) throws PyException { * * @param index index of the element to set. * @param value to set this element to, regarded as a buffer of length one unit. - * @throws PyException(AttributeError) if value cannot be converted to an integer - * @throws PyException(ValueError) if value<0 or value>255 + * @throws PyException {@code AttributeError} if value cannot be converted to an integer + * @throws PyException {@code ValueError} if value<0 or value>255 */ @Override public synchronized void pyset(int index, PyObject value) throws PyException { diff --git a/src/org/python/core/PyMethodDescr.java b/src/org/python/core/PyMethodDescr.java index 4347b6299..3638eb853 100644 --- a/src/org/python/core/PyMethodDescr.java +++ b/src/org/python/core/PyMethodDescr.java @@ -1,3 +1,5 @@ +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; import org.python.expose.ExposedGet; @@ -17,7 +19,7 @@ public PyMethodDescr(PyType t, PyBuiltinCallable func) { minargs = func.info.getMinargs(); maxargs = func.info.getMaxargs(); meth = func; - meth.setInfo(this); + meth.setInfo(this); // XXX Why modify func.info each time used? } @ExposedGet(name = "__doc__") @@ -25,10 +27,12 @@ public String getDoc() { return meth.getDoc(); } + @Override public int getMaxargs() { return maxargs; } + @Override public int getMinargs() { return minargs; } @@ -54,6 +58,7 @@ final PyObject method_descriptor___call__(PyObject[] args, String[] kwargs) { return meth.bind(args[0]).__call__(actualArgs, kwargs); } + @Override public PyException unexpectedCall(int nargs, boolean keywords) { return PyBuiltinCallable.DefaultInfo.unexpectedCall(nargs, keywords, name, minargs, maxargs); @@ -78,6 +83,7 @@ final PyObject method_descriptor___get__(PyObject obj, PyObject type) { * * @return a name String */ + @Override @ExposedGet(name = "__name__") public String getName() { return name; diff --git a/src/org/python/core/PyModule.java b/src/org/python/core/PyModule.java index 45a45c7ff..1a3f818b2 100644 --- a/src/org/python/core/PyModule.java +++ b/src/org/python/core/PyModule.java @@ -14,7 +14,7 @@ */ @ExposedType(name = "module") public class PyModule extends PyObject implements Traverseproc { - private final PyObject moduleDoc = new PyString( + private final PyObject moduleDoc = new PyString( //FIXME: not used (and not static) "module(name[, doc])\n" + "\n" + "Create a module object.\n" + @@ -88,49 +88,130 @@ public void delDict() { throw Py.TypeError("readonly attribute"); } + /** + * {@inheritDoc} + *

    + * Overridden in {@code PyModule} to search for a sub-module of this module (using the key + * {@code ".".join(self.__name__, name)}) in {@code sys.modules}, on the {@code self.__path__}, + * and as a Java package with the same name. The named sub-module becomes an attribute of this + * module (in {@code __dict__}). + */ @Override protected PyObject impAttr(String name) { - if (__dict__ == null) { - return null; - } - PyObject path = __dict__.__finditem__("__path__"); - if (path == null) { - path = new PyList(); - } - PyObject pyName = __dict__.__finditem__("__name__"); - if (pyName == null) { - return null; - } - String fullName = (pyName.__str__().toString() + '.' + name).intern(); - PyObject modules = Py.getSystemState().modules; - PyObject attr = modules.__finditem__(fullName); + // Some of our look-up needs the full name, deduced from __name__ and name. + String fullName = getFullName(name); + + if (fullName != null) { + // Maybe the attribute is a Python sub-module + PyObject attr = findSubModule(name, fullName); - if (path instanceof PyList) { + // Or is a Java package if (attr == null) { - attr = imp.find_module(name, fullName, (PyList)path); + // Still looking: maybe it's a Java package? + attr = PySystemState.packageManager.lookupName(fullName); } - } else if (path != Py.None) { - throw Py.TypeError("__path__ must be list or None"); + + // Add as an attribute the thing we found (if not still null) + return addedSubModule(name, fullName, attr); } + return null; + } - if (attr == null) { - attr = PySystemState.packageManager.lookupName(fullName); + /** + * Find Python sub-module within this object, within {@code sys.modules} or along this module's + * {@code __path__}. + * + * @param name simple name of sub package + * @param fullName of sub package + * @return module found or {@code null} + */ + private PyObject findSubModule(String name, String fullName) { + PyObject attr = null; + if (fullName != null) { + // The module may already have been loaded in sys.modules + attr = Py.getSystemState().modules.__finditem__(fullName); + // Or it may be found as a Python module along this module's __path__ + if (attr == null) { + PyObject path = __dict__.__finditem__("__path__"); + if (path == null) { + attr = imp.find_module(name, fullName, new PyList()); + } else if (path instanceof PyList) { + attr = imp.find_module(name, fullName, (PyList) path); + } else if (path != Py.None) { + throw Py.TypeError("__path__ must be list or None"); + } + } } + return attr; + } + /** + * Add the given attribute to {@code __dict__}, if it is not {@code null} allowing + * {@code sys.modules[fullName]} to override. + * + * @param name of attribute to add + * @param fullName by which to check in {@code sys.modules} + * @param attr attribute to add (if not overridden) + * @return attribute value actually added (may be from {@code sys.modules}) or {@code null} + */ + private PyObject addedSubModule(String name, String fullName, PyObject attr) { if (attr != null) { - // Allow a package component to change its own meaning - PyObject found = modules.__finditem__(fullName); - if (found != null) { - attr = found; + if (fullName != null) { + // If a module by the full name exists in sys.modules, that takes precedence. + PyObject entry = Py.getSystemState().modules.__finditem__(fullName); + if (entry != null) { + attr = entry; + } } + // Enter this as an attribute of this module. __dict__.__setitem__(name, attr); - return attr; } + return attr; + } + /** + * Construct (and intern) the full name of a possible sub-module of this one, using the + * {@code __name__} attribute and a simple sub-module name. Return {@code null} if any of these + * requirements is missing. + * + * @param name simple name of (possible) sub-module + * @return interned full name or {@code null} + */ + private String getFullName(String name) { + if (__dict__ != null) { + PyObject pyName = __dict__.__finditem__("__name__"); + if (pyName != null && name != null && name.length() > 0) { + return (pyName.__str__().toString() + '.' + name).intern(); + } + } return null; } + /** + * {@inheritDoc} + *

    + * Overridden in {@code PyModule} so that if the base-class {@code __findattr_ex__} is + * unsuccessful, it will to search for the named attribute as a Java sub-package. This is + * responsible for the automagical import of Java (but not Python) packages when referred to as + * attributes. + */ + @Override + public PyObject __findattr_ex__(String name) { + // Find the attribute in the dictionary + PyObject attr = super.__findattr_ex__(name); + if (attr == null) { + // The attribute may be a Java sub-package to auto-import. + String fullName = getFullName(name); + if (fullName != null) { + attr = PySystemState.packageManager.lookupName(fullName); + // Any entry in sys.modules to takes precedence. + attr = addedSubModule(name, fullName, attr); + } + } + return attr; + } + @Override public void __setattr__(String name, PyObject value) { module___setattr__(name, value); @@ -190,8 +271,7 @@ public PyObject __dir__() { d = __dict__; } if (d == null || - !(d instanceof PyDictionary || - d instanceof PyStringMap || + !(d instanceof AbstractDict || d instanceof PyDictProxy)) { throw Py.TypeError(String.format("%.200s.__dict__ is not a dictionary", getType().fastGetName().toLowerCase())); @@ -206,17 +286,15 @@ private void ensureDict() { } /** - * Delegates to {@link #newJ(PyModule, Class, Object...)}, .
    - * For keywords-support use {@link #newJ(Class, String[], Object...)}. + * Delegates to {@link Py#newJ(PyModule, Class, Object...)}. For keyword support use + * {@link #newJ(Class, String[], Object...)}. * - * {@see #newJ(Class, String[], Object...)} - * {@see org.python.core.Py#newJ(PyModule, Class, Object...)} - * {@see org.python.core.Py#newJ(PyModule, Class, String[], Object...)} - * {@see org.python.core.Py#newJ(PyObject, Class, PyObject[], String[])} - * {@see org.python.core.Py#newJ(PyObject, Class, Object...)} - * {@see org.python.core.Py#newJ(PyObject, Class, String[], Object...)} + * @see #newJ(Class, String[], Object...) + * @see Py#newJ(PyModule, Class, String[], Object...) + * @see Py#newJ(PyObject, Class, PyObject[], String[]) + * @see Py#newJ(PyObject, Class, Object...) + * @see Py#newJ(PyObject, Class, String[], Object...) * - * @param module the module containing the desired class * @param jcls Java-type of the desired clas, must have the same name * @param args constructor-arguments * @return a new instance of the desired class @@ -227,15 +305,14 @@ public T newJ(Class jcls, Object... args) { } /** - * Delgates to {@link org.python.core.Py#newJ(PyModule, Class, String[], Object...)}.
    - * {@code keywordss} are applied to the last {@code args} in the list. + * Delgates to {@link org.python.core.Py#newJ(PyModule, Class, String[], Object...)}. + * {@code keywords} are applied to the last {@code args} in the list. * - * {@see #newJ(Class, Object...)} - * {@see org.python.core.Py#newJ(PyModule, Class, Object...)} - * {@see org.python.core.Py#newJ(PyModule, Class, String[], Object...)} - * {@see org.python.core.Py#newJ(PyObject, Class, PyObject[], String[])} - * {@see org.python.core.Py#newJ(PyObject, Class, Object...)} - * {@see org.python.core.Py#newJ(PyObject, Class, String[], Object...)} + * @see #newJ(Class, Object...) + * @see Py#newJ(PyModule, Class, String[], Object...) + * @see Py#newJ(PyObject, Class, PyObject[], String[]) + * @see Py#newJ(PyObject, Class, Object...) + * @see Py#newJ(PyObject, Class, String[], Object...) * * @param jcls Java-type of the desired class, must have the same name * @param keywords are applied to the last {@code args} in the list @@ -247,7 +324,6 @@ public T newJ(Class jcls, String[] keywords, Object... args) { return Py.newJ(this, jcls, keywords, args); } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { diff --git a/src/org/python/core/PyNone.java b/src/org/python/core/PyNone.java index 9674f0c6f..f20e640a4 100644 --- a/src/org/python/core/PyNone.java +++ b/src/org/python/core/PyNone.java @@ -1,7 +1,5 @@ -/* - * Copyright (c) Corporation for National Research Initiatives - * Copyright (c) Jython Developers - */ +// Copyright (c) Corporation for National Research Initiatives +// Copyright (c) Jython Developers package org.python.core; import java.io.Serializable; @@ -18,8 +16,16 @@ public class PyNone extends PyObject implements Serializable { public static final PyType TYPE = PyType.fromClass(PyNone.class); - PyNone() { - super(TYPE); + private PyNone() {/* Not super(TYPE): TYPE is null until too late in bootstrapping. */} + + private static class Holder { + + /** The unique instance of PyNone. */ + static final PyNone INSTANCE = new PyNone(); + } + + static PyNone getInstance() { + return Holder.INSTANCE; } @Override diff --git a/src/org/python/core/PyNullImporter.java b/src/org/python/core/PyNullImporter.java index 01539c289..c9e5dd573 100644 --- a/src/org/python/core/PyNullImporter.java +++ b/src/org/python/core/PyNullImporter.java @@ -20,11 +20,10 @@ public class PyNullImporter extends PyObject { public PyNullImporter(PyObject pathObj) { super(); - String pathStr = asPath(pathObj); + String pathStr = imp.fileSystemDecode(pathObj); if (pathStr.equals("")) { throw Py.ImportError("empty pathname"); - } - if (isDir(pathStr)) { + } else if (isDir(pathStr)) { throw Py.ImportError("existing directory: " + pathStr); } } @@ -42,17 +41,6 @@ final PyObject NullImporter_find_module(String fullname, String path) { return Py.None; } - // FIXME Refactoring move helper function to a central util library - // FIXME Also can take in account working in zip file systems - - private static String asPath(PyObject pathObj) { - if (!(pathObj instanceof PyString)) { - throw Py.TypeError(String.format("coercing to Unicode: need string, %s type found", - pathObj.getType().fastGetName())); - } - return pathObj.toString(); - } - private static boolean isDir(String pathStr) { if (pathStr.equals("")) { return false; diff --git a/src/org/python/core/PyObject.java b/src/org/python/core/PyObject.java index f93165d74..a357a3866 100644 --- a/src/org/python/core/PyObject.java +++ b/src/org/python/core/PyObject.java @@ -15,12 +15,12 @@ import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import org.python.util.Generic; import org.python.modules.gc; +import org.python.util.Generic; /** - * All objects known to the Jython runtime system are represented by an instance - * of the class {@code PyObject} or one of its subclasses. + * All objects known to the Jython runtime system are represented by an instance of the class + * {@code PyObject} or one of its subclasses. */ @ExposedType(name = "object", doc = BuiltinDocs.object_doc) public class PyObject implements Serializable { @@ -28,31 +28,25 @@ public class PyObject implements Serializable { public static final PyType TYPE = PyType.fromClass(PyObject.class); /** - * This should have been suited at {@link org.python.modules.gc}, - * but that would cause a dependency cycle in the init-phases of - * {@code gc.class} and {@code PyObject.class}. Now this boolean - * mirrors the presence of the - * {@link org.python.modules.gc#MONITOR_GLOBAL}-flag in Jython's - * gc module.
    + * This should have been suited at {@link org.python.modules.gc}, but that would cause a + * dependency cycle in the init-phases of {@code gc.class} and {@code PyObject.class}. Now this + * boolean mirrors the presence of the {@link org.python.modules.gc#MONITOR_GLOBAL}-flag in + * Jython's gc module.
    *
    * Do not change manually. */ public static boolean gcMonitorGlobal = false; - /** The type of this object. - */ + /** The type of this object. */ protected PyType objtype; /** - * {@code attributes} is a general purpose linked list of arbitrary - * Java objects that should be kept alive by this PyObject. These - * objects can be accessed by the methods and keys in - * {@link org.python.core.JyAttribute}. - * A notable attribute is the javaProxy (accessible via - * {@code JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)}), - * an underlying Java instance that this object is wrapping or is a - * subclass of. Anything attempting to use the proxy should go through - * {@link #getJavaProxy()} which ensures that it's initialized. + * {@code attributes} is a general purpose linked list of arbitrary Java objects that should be + * kept alive by this PyObject. These objects can be accessed by the methods and keys in + * {@link org.python.core.JyAttribute}. A notable attribute is the javaProxy (accessible via + * {@code JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)}), an underlying Java instance + * that this object is wrapping or is a subclass of. Anything attempting to use the proxy should + * go through {@link #getJavaProxy()} which ensures that it's initialized. * * @see org.python.core.JyAttribute * @see org.python.core.JyAttribute#JAVA_PROXY_ATTR @@ -73,16 +67,14 @@ public class PyObject implements Serializable { primitiveMap.put(Float.TYPE, Float.class); primitiveMap.put(Double.TYPE, Double.class); - if (BootstrapTypesSingleton.getInstance().size() > 0) { - Py.writeWarning("init", "Bootstrap types weren't encountered in bootstrapping: " - + BootstrapTypesSingleton.getInstance()); - } + PyType.ensureBootstrapped(); } public PyObject(PyType objtype) { this.objtype = objtype; - if (gcMonitorGlobal) + if (gcMonitorGlobal) { gc.monitorObject(this); + } } /** @@ -90,9 +82,10 @@ public PyObject(PyType objtype) { * field to correspond to the specific subclass of PyObject being instantiated. **/ public PyObject() { - objtype = PyType.fromClass(getClass(), false); - if (gcMonitorGlobal) + objtype = PyType.fromClass(getClass()); + if (gcMonitorGlobal) { gc.monitorObject(this); + } } /** @@ -100,14 +93,15 @@ public PyObject() { * distinct. */ PyObject(boolean ignored) { - objtype = (PyType)this; - if (gcMonitorGlobal) + objtype = (PyType) this; + if (gcMonitorGlobal) { gc.monitorObject(this); + } } @ExposedNew static final PyObject object___new__(PyNewWrapper new_, boolean init, PyType subtype, - PyObject[] args, String[] keywords) { + PyObject[] args, String[] keywords) { // don't allow arguments if the default object.__init__() is about to be called PyObject[] where = new PyObject[1]; subtype.lookup_where("__init__", where); @@ -117,37 +111,33 @@ static final PyObject object___new__(PyNewWrapper new_, boolean init, PyType sub if (subtype.isAbstract()) { // Compute ", ".join(sorted(type.__abstractmethods__)) into methods - PyObject sorted = - Py.getSystemState().getBuiltins().__getitem__(Py.newString("sorted")); + PyObject sorted = Py.getSystemState().getBuiltins().__getitem__(Py.newString("sorted")); PyString methods = - Py.newString(", ") - .join(sorted.__call__(subtype.getAbstractmethods())); - throw Py.TypeError(String.format("Can't instantiate abstract class %s with abstract " - + "methods %s", subtype.fastGetName(), methods)); + Py.newString(", ").join(sorted.__call__(subtype.getAbstractmethods())); + throw Py.TypeError(String.format( + "Can't instantiate abstract class %s with abstract " + "methods %s", + subtype.fastGetName(), methods)); } return new_.for_type == subtype ? new PyObject() : new PyObjectDerived(subtype); } /** + * From Jython 2.7 on, {@code PyObject}s must not have finalizers directly. If a finalizer, + * a.k.a. {@code __del__} is needed, follow the instructions in the documentation of + * {@link org.python.core.finalization.FinalizablePyObject}. *

    - * From Jython 2.7 on, {@code PyObject}s must not have finalizers directly. - * If a finalizer, a.k.a. {@code __del__} is needed, follow the instructions in the - * documentation of {@link org.python.core.finalization.FinalizablePyObject}. - *

    - *

    - * Note that this empty finalizer implementation is optimized away by the JVM - * (See {@link http://www.javaspecialists.eu/archive/Issue170.html}). - * So {@code PyObject}s are not expensively treated as finalizable objects by the - * Java-GC. Its single intention is to prevent subclasses from having Java-style - * finalizers. - *

    + * Note that this empty finalizer implementation is optimized away by the JVM. (See Discovering Objects with Non-trivial + * Finalizers). So {@code PyObject}s are not expensively treated as finalizable objects by + * the Java-GC. Its single intention is to prevent subclasses from having Java-style finalizers. */ + @SuppressWarnings("deprecation") // See the Javadoc + @Override protected final void finalize() throws Throwable {} @ExposedMethod(doc = BuiltinDocs.object___init___doc) - final void object___init__(PyObject[] args, String[] keywords) { - } + final void object___init__(PyObject[] args, String[] keywords) {} @ExposedGet(name = "__class__") public PyType getType() { @@ -173,11 +163,8 @@ public PyObject fastGetClass() { return objtype; } - /** - * Dispatch __init__ behavior - */ - public void dispatch__init__(PyObject[] args, String[] keywords) { - } + /** Dispatch __init__ behavior */ + public void dispatch__init__(PyObject[] args, String[] keywords) {} /** * Attempts to automatically initialize our Java proxy if we have one and it wasn't initialized @@ -190,23 +177,22 @@ void proxyInit() { return; } if (!PyProxy.class.isAssignableFrom(c)) { - throw Py.SystemError("Automatic proxy initialization should only occur on proxy classes"); + throw Py.SystemError( + "Automatic proxy initialization should only occur on proxy classes"); } PyProxy proxy; Object[] previous = ThreadContext.initializingProxy.get(); - ThreadContext.initializingProxy.set(new Object[] { this }); + ThreadContext.initializingProxy.set(new Object[] {this}); try { try { - proxy = (PyProxy)c.newInstance(); - } catch (java.lang.InstantiationException e) { + proxy = (PyProxy) c.getDeclaredConstructor().newInstance(); + } catch (InstantiationException | NoSuchMethodException e) { Class sup = c.getSuperclass(); - String msg = "Default constructor failed for Java superclass"; + String msg = "Default constructor failed/missing for Java superclass"; if (sup != null) { msg += " " + sup.getName(); } throw Py.TypeError(msg); - } catch (NoSuchMethodError nsme) { - throw Py.TypeError("constructor requires arguments"); } catch (Exception exc) { throw Py.JavaError(exc); } @@ -225,14 +211,21 @@ void proxyInit() { } /** - * Equivalent to the standard Python __repr__ method. This method - * should not typically need to be overrriden. The easiest way to - * configure the string representation of a PyObject is to - * override the standard Java toString method. + * Equivalent to the standard Python __repr__ method. Each sub-class of + * PyObject is likely to re-define this method to provide for its own reproduction. **/ - // counter-intuitively exposing this as __str__, otherwise stack overflow - // occurs during regression testing. XXX: more detail for this comment - // is needed. + /* + * The effect of exposing __repr__ as __str__ is that a Python call to o.__str__() will land + * here. (A Java call to o.__str__() lands here too because __str__ is defined to call + * __repr__.) This will continue to be true in any sub-class that does not expose a __str__ of + * its own. (Such a class should override Java __str__ to call the method exposed as Python + * __str__.) Note that we expose a non-final method, therefore in a class that (Java-)overrides + * __repr__, Python (and Java) calls like o.__str__() will land on the overridden __repr__. + * + * This design, though long-standing, has caused confusion to the implementors of types, and + * seems to make *Derived.java classes more complicated. We should seek a more transparent + * design. + */ @ExposedMethod(names = "__str__", doc = BuiltinDocs.object___str___doc) public PyString __repr__() { return new PyString(toString()); @@ -262,34 +255,33 @@ final String object_toString() { } /** - * Equivalent to the standard Python __str__ method. This method - * should not typically need to be overridden. The easiest way to - * configure the string representation of a PyObject is to - * override the standard Java toString method. + * Equivalent to the standard Python __str__ method. The default implementation (in + * PyObject) calls {@link #__repr__()}, making it unnecessary to override + * __str__ in sub-classes of PyObject where both forms are the same. A + * common choice is to provide the same implementation to __str__ and + * toString, for consistency in the printed form of objects between Python and + * Java. **/ public PyString __str__() { return __repr__(); } /** - * PyObjects that implement - * org.python.core.finalization.HasFinalizeTrigger - * shall implement this method via:
    + * PyObjects that implement org.python.core.finalization.HasFinalizeTrigger shall + * implement this method via:
    * FinalizeTrigger.ensureFinalizer(this); **/ @ExposedMethod - public void __ensure_finalizer__() { - } + public void __ensure_finalizer__() {} public PyUnicode __unicode__() { return new PyUnicode(__str__()); } /** - * Equivalent to the standard Python __hash__ method. This method can - * not be overridden. Instead, you should override the standard Java - * hashCode method to return an appropriate hash code for - * the PyObject. + * Equivalent to the standard Python __hash__ method. This method can not be overridden. + * Instead, you should override the standard Java hashCode method to return an + * appropriate hash code for the PyObject. **/ public final PyInteger __hash__() { return new PyInteger(hashCode()); @@ -306,32 +298,29 @@ final int object___hash__() { } /** - * Should almost never be overridden. - * If overridden, it is the subclasses responsibility to ensure that - * a.equals(b) == true iff cmp(a,b) == 0 + * Should almost never be overridden. If overridden, it is the subclasses responsibility to + * ensure that a.equals(b) == true iff cmp(a,b) == 0 **/ @Override public boolean equals(Object ob_other) { - if(ob_other == this) { + if (ob_other == this) { return true; } - return (ob_other instanceof PyObject) && _eq((PyObject)ob_other).__nonzero__(); + return (ob_other instanceof PyObject) && _eq((PyObject) ob_other).__nonzero__(); } /** - * Equivalent to the standard Python __nonzero__ method. Returns whether of - * not a given PyObject is considered true. + * Equivalent to the standard Python __nonzero__ method. Returns whether of not a given + * PyObject is considered true. */ public boolean __nonzero__() { return true; } /** - * Equivalent to the Jython __tojava__ method. - * Tries to coerce this object to an instance of the requested Java class. - * Returns the special object Py.NoConversion - * if this PyObject can not be converted to the - * desired Java class. + * Equivalent to the Jython __tojava__ method. Tries to coerce this object to an instance of the + * requested Java class. Returns the special object Py.NoConversion if this + * PyObject can not be converted to the desired Java class. * * @param c the Class to convert this PyObject to. **/ @@ -354,8 +343,8 @@ public Object __tojava__(Class c) { } // convert faux floats - // XXX: should also convert faux ints, but that breaks test_java_visibility - // (ReflectedArgs resolution) + // XXX: should also convert faux ints, but that breaks test_java_visibility (ReflectedArgs + // resolution) if (c == Double.class || c == Float.class) { try { return __float__().asDouble(); @@ -397,12 +386,10 @@ protected Object getJavaProxy() { /** * The basic method to override when implementing a callable object. * - * The first len(args)-len(keywords) members of args[] are plain - * arguments. The last len(keywords) arguments are the values of the - * keyword arguments. + * The first len(args)-len(keywords) members of args[] are plain arguments. The last + * len(keywords) arguments are the values of the keyword arguments. * - * @param args all arguments to the function (including - * keyword arguments). + * @param args all arguments to the function (including keyword arguments). * @param keywords the keywords used for all keyword arguments. **/ public PyObject __call__(PyObject args[], String keywords[]) { @@ -414,17 +401,14 @@ public PyObject __call__(ThreadState state, PyObject args[], String keywords[]) } /** - * A variant of the __call__ method with one extra initial argument. - * This variant is used to allow method invocations to be performed - * efficiently. + * A variant of the __call__ method with one extra initial argument. This variant is used to + * allow method invocations to be performed efficiently. * - * The default behavior is to invoke __call__(args, - * keywords) with the appropriate arguments. The only reason to - * override this function would be for improved performance. + * The default behavior is to invoke __call__(args, keywords) with the appropriate + * arguments. The only reason to override this function would be for improved performance. * - * @param arg1 the first argument to the function. - * @param args the last arguments to the function (including - * keyword arguments). + * @param arg1 the first argument to the function. + * @param args the last arguments to the function (including keyword arguments). * @param keywords the keywords used for all keyword arguments. **/ public PyObject __call__(PyObject arg1, PyObject args[], String keywords[]) { @@ -439,12 +423,11 @@ public PyObject __call__(ThreadState state, PyObject arg1, PyObject args[], Stri } /** - * A variant of the __call__ method when no keywords are passed. The - * default behavior is to invoke __call__(args, keywords) - * with the appropriate arguments. The only reason to override this - * function would be for improved performance. + * A variant of the __call__ method when no keywords are passed. The default behavior is to + * invoke __call__(args, keywords) with the appropriate arguments. The only reason + * to override this function would be for improved performance. * - * @param args all arguments to the function. + * @param args all arguments to the function. **/ public PyObject __call__(PyObject args[]) { return __call__(args, Py.NoKeywords); @@ -455,10 +438,9 @@ public PyObject __call__(ThreadState state, PyObject args[]) { } /** - * A variant of the __call__ method with no arguments. The default - * behavior is to invoke __call__(args, keywords) with the - * appropriate arguments. The only reason to override this function - * would be for improved performance. + * A variant of the __call__ method with no arguments. The default behavior is to invoke + * __call__(args, keywords) with the appropriate arguments. The only reason to + * override this function would be for improved performance. **/ public PyObject __call__() { return __call__(Py.EmptyObjects, Py.NoKeywords); @@ -469,15 +451,14 @@ public PyObject __call__(ThreadState state) { } /** - * A variant of the __call__ method with one argument. The default - * behavior is to invoke __call__(args, keywords) with the - * appropriate arguments. The only reason to override this function - * would be for improved performance. + * A variant of the __call__ method with one argument. The default behavior is to invoke + * __call__(args, keywords) with the appropriate arguments. The only reason to + * override this function would be for improved performance. * - * @param arg0 the single argument to the function. + * @param arg0 the single argument to the function. **/ public PyObject __call__(PyObject arg0) { - return __call__(new PyObject[] { arg0 }, Py.NoKeywords); + return __call__(new PyObject[] {arg0}, Py.NoKeywords); } public PyObject __call__(ThreadState state, PyObject arg0) { @@ -485,16 +466,15 @@ public PyObject __call__(ThreadState state, PyObject arg0) { } /** - * A variant of the __call__ method with two arguments. The default - * behavior is to invoke __call__(args, keywords) with the - * appropriate arguments. The only reason to override this function - * would be for improved performance. + * A variant of the __call__ method with two arguments. The default behavior is to invoke + * __call__(args, keywords) with the appropriate arguments. The only reason to + * override this function would be for improved performance. * - * @param arg0 the first argument to the function. - * @param arg1 the second argument to the function. + * @param arg0 the first argument to the function. + * @param arg1 the second argument to the function. **/ public PyObject __call__(PyObject arg0, PyObject arg1) { - return __call__(new PyObject[] { arg0, arg1 }, Py.NoKeywords); + return __call__(new PyObject[] {arg0, arg1}, Py.NoKeywords); } public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1) { @@ -502,17 +482,16 @@ public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1) { } /** - * A variant of the __call__ method with three arguments. The default - * behavior is to invoke __call__(args, keywords) with the - * appropriate arguments. The only reason to override this function - * would be for improved performance. + * A variant of the __call__ method with three arguments. The default behavior is to invoke + * __call__(args, keywords) with the appropriate arguments. The only reason to + * override this function would be for improved performance. * - * @param arg0 the first argument to the function. - * @param arg1 the second argument to the function. - * @param arg2 the third argument to the function. + * @param arg0 the first argument to the function. + * @param arg1 the second argument to the function. + * @param arg2 the third argument to the function. **/ public PyObject __call__(PyObject arg0, PyObject arg1, PyObject arg2) { - return __call__(new PyObject[] { arg0, arg1, arg2 }, Py.NoKeywords); + return __call__(new PyObject[] {arg0, arg1, arg2}, Py.NoKeywords); } public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1, PyObject arg2) { @@ -520,30 +499,26 @@ public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1, PyObje } /** - * A variant of the __call__ method with four arguments. The default - * behavior is to invoke __call__(args, keywords) with the - * appropriate arguments. The only reason to override this function - * would be for improved performance. + * A variant of the __call__ method with four arguments. The default behavior is to invoke + * __call__(args, keywords) with the appropriate arguments. The only reason to + * override this function would be for improved performance. * - * @param arg0 the first argument to the function. - * @param arg1 the second argument to the function. - * @param arg2 the third argument to the function. - * @param arg3 the fourth argument to the function. + * @param arg0 the first argument to the function. + * @param arg1 the second argument to the function. + * @param arg2 the third argument to the function. + * @param arg3 the fourth argument to the function. **/ public PyObject __call__(PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3) { - return __call__( - new PyObject[] { arg0, arg1, arg2, arg3 }, - Py.NoKeywords); + return __call__(new PyObject[] {arg0, arg1, arg2, arg3}, Py.NoKeywords); } - public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3) { + public PyObject __call__(ThreadState state, PyObject arg0, PyObject arg1, PyObject arg2, + PyObject arg3) { return __call__(arg0, arg1, arg2, arg3); } - public PyObject _callextra(PyObject[] args, - String[] keywords, - PyObject starargs, - PyObject kwargs) { + public PyObject _callextra(PyObject[] args, String[] keywords, PyObject starargs, + PyObject kwargs) { int argslen = args.length; @@ -551,30 +526,28 @@ public PyObject _callextra(PyObject[] args, if (this instanceof PyFunction) { name = ((PyFunction) this).__name__ + "() "; } else if (this instanceof PyBuiltinCallable) { - name = ((PyBuiltinCallable)this).fastGetName().toString() + "() "; + name = ((PyBuiltinCallable) this).fastGetName().toString() + "() "; } else { name = getType().fastGetName() + " "; } if (kwargs != null) { PyObject keys = kwargs.__findattr__("keys"); - if(keys == null) - throw Py.TypeError(name - + "argument after ** must be a mapping"); - for (String keyword : keywords) - if (kwargs.__finditem__(keyword) != null) + if (keys == null) { + throw Py.TypeError(name + "argument after ** must be a mapping"); + } + for (String keyword : keywords) { + if (kwargs.__finditem__(keyword) != null) { throw Py.TypeError( - name - + "got multiple values for " - + "keyword argument '" - + keyword - + "'"); + name + "got multiple values for keyword argument '" + keyword + "'"); + } + } argslen += kwargs.__len__(); } List starObjs = null; if (starargs != null) { starObjs = new ArrayList(); PyObject iter = Py.iter(starargs, name + "argument after * must be a sequence"); - for (PyObject cur = null; ((cur = iter.__iternext__()) != null); ) { + for (PyObject cur = null; ((cur = iter.__iternext__()) != null);) { starObjs.add(cur); } argslen += starObjs.size(); @@ -582,31 +555,26 @@ public PyObject _callextra(PyObject[] args, PyObject[] newargs = new PyObject[argslen]; int argidx = args.length - keywords.length; System.arraycopy(args, 0, newargs, 0, argidx); - if(starObjs != null) { + if (starObjs != null) { Iterator it = starObjs.iterator(); - while(it.hasNext()) { + while (it.hasNext()) { newargs[argidx++] = it.next(); } } - System.arraycopy(args, - args.length - keywords.length, - newargs, - argidx, - keywords.length); + System.arraycopy(args, args.length - keywords.length, newargs, argidx, keywords.length); argidx += keywords.length; if (kwargs != null) { - String[] newkeywords = - new String[keywords.length + kwargs.__len__()]; + String[] newkeywords = new String[keywords.length + kwargs.__len__()]; System.arraycopy(keywords, 0, newkeywords, 0, keywords.length); PyObject keys = kwargs.invoke("keys"); PyObject key; - for (int i = 0;(key = keys.__finditem__(i)) != null; i++) { - if (!(key instanceof PyString)) + for (int i = 0; (key = keys.__finditem__(i)) != null; i++) { + if (!(key instanceof PyString)) { throw Py.TypeError(name + "keywords must be strings"); - newkeywords[keywords.length + i] = - ((PyString) key).internedString(); + } + newkeywords[keywords.length + i] = ((PyString) key).internedString(); newargs[argidx++] = kwargs.__finditem__(key); } keywords = newkeywords; @@ -615,8 +583,9 @@ public PyObject _callextra(PyObject[] args, if (newargs.length != argidx) { args = new PyObject[argidx]; System.arraycopy(newargs, 0, args, 0, argidx); - } else + } else { args = newargs; + } return __call__(args, keywords); } @@ -660,39 +629,35 @@ public boolean isIndex() { /* The basic functions to implement a mapping */ /** - * Equivalent to the standard Python __len__ method. - * Part of the mapping discipline. + * Equivalent to the standard Python __len__ method. Part of the mapping discipline. * * @return the length of the object **/ public int __len__() { - throw Py.TypeError(String.format("object of type '%.200s' has no len()", - getType().fastGetName())); + throw Py.TypeError( + String.format("object of type '%.200s' has no len()", getType().fastGetName())); } /** - * Very similar to the standard Python __getitem__ method. - * Instead of throwing a KeyError if the item isn't found, - * this just returns null. + * Very similar to the standard Python __getitem__ method. Instead of throwing a KeyError if the + * item isn't found, this just returns null. * - * Classes that wish to implement __getitem__ should - * override this method instead (with the appropriate - * semantics. + * Classes that wish to implement __getitem__ should override this method instead (with the + * appropriate semantics. * * @param key the key to lookup in this container * * @return the value corresponding to key or null if key is not found **/ public PyObject __finditem__(PyObject key) { - throw Py.TypeError(String.format("'%.200s' object is unsubscriptable", - getType().fastGetName())); + throw Py.TypeError( + String.format("'%.200s' object is unsubscriptable", getType().fastGetName())); } /** - * A variant of the __finditem__ method which accepts a primitive - * int as the key. By default, this method will call - * __finditem__(PyObject key) with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __finditem__ method which accepts a primitive int as the key. + * By default, this method will call __finditem__(PyObject key) with the + * appropriate args. The only reason to override this method is for performance. * * @param key the key to lookup in this sequence. * @return the value corresponding to key or null if key is not found. @@ -704,15 +669,13 @@ public PyObject __finditem__(int key) { } /** - * A variant of the __finditem__ method which accepts a Java - * String as the key. By default, this method will call - * __finditem__(PyObject key) with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __finditem__ method which accepts a Java String as the key. By + * default, this method will call __finditem__(PyObject key) with the appropriate + * args. The only reason to override this method is for performance. * * Warning: key must be an interned string!!!!!!!! * - * @param key the key to lookup in this sequence - - * must be an interned string . + * @param key the key to lookup in this sequence - must be an interned string . * @return the value corresponding to key or null if key is not found. * * @see #__finditem__(PyObject) @@ -722,32 +685,31 @@ public PyObject __finditem__(String key) { } /** - * Equivalent to the standard Python __getitem__ method. - * This variant takes a primitive int as the key. - * This method should not be overridden. - * Override the __finditem__ method instead. + * Equivalent to the standard Python __getitem__ method. This variant takes a primitive + * int as the key. This method should not be overridden. Override the + * __finditem__ method instead. * * @param key the key to lookup in this container. * @return the value corresponding to that key. - * @exception Py.KeyError if the key is not found. + * @throws PyException {@code KeyError} if the key is not found. * * @see #__finditem__(int) **/ public PyObject __getitem__(int key) { PyObject ret = __finditem__(key); - if (ret == null) + if (ret == null) { throw Py.KeyError("" + key); + } return ret; } /** - * Equivalent to the standard Python __getitem__ method. - * This method should not be overridden. + * Equivalent to the standard Python __getitem__ method. This method should not be overridden. * Override the __finditem__ method instead. * * @param key the key to lookup in this container. * @return the value corresponding to that key. - * @exception Py.KeyError if the key is not found. + * @throws PyException {@code KeyError} if the key is not found. * * @see #__finditem__(PyObject) **/ @@ -767,19 +729,16 @@ public PyObject __getitem__(PyObject key) { **/ public void __setitem__(PyObject key, PyObject value) { throw Py.TypeError(String.format("'%.200s' object does not support item assignment", - getType().fastGetName())); + getType().fastGetName())); } /** - * A variant of the __setitem__ method which accepts a String - * as the key. This String must be interned. - * By default, this will call - * __setitem__(PyObject key, PyObject value) - * with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __setitem__ method which accepts a String as the key. This String must be + * interned. By default, this will call + * __setitem__(PyObject key, PyObject value) with the appropriate args. The only + * reason to override this method is for performance. * - * @param key the key whose value will be set - - * must be an interned string . + * @param key the key whose value will be set - must be an interned string . * @param value the value to set this key to * * @see #__setitem__(PyObject, PyObject) @@ -789,12 +748,9 @@ public void __setitem__(String key, PyObject value) { } /** - * A variant of the __setitem__ method which accepts a primitive - * int as the key. - * By default, this will call - * __setitem__(PyObject key, PyObject value) - * with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __setitem__ method which accepts a primitive int as the key. By + * default, this will call __setitem__(PyObject key, PyObject value) with the + * appropriate args. The only reason to override this method is for performance. * * @param key the key whose value will be set * @param value the value to set this key to @@ -809,24 +765,20 @@ public void __setitem__(int key, PyObject value) { * Equivalent to the standard Python __delitem__ method. * * @param key the key to be removed from the container - * @exception Py.KeyError if the key is not found in the container + * @throws PyException {@code KeyError} if the key is not found in the container **/ public void __delitem__(PyObject key) { throw Py.TypeError(String.format("'%.200s' object doesn't support item deletion", - getType().fastGetName())); + getType().fastGetName())); } /** - * A variant of the __delitem__ method which accepts a String - * as the key. This String must be interned. - * By default, this will call - * __delitem__(PyObject key) - * with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __delitem__ method which accepts a String as the key. This String must be + * interned. By default, this will call __delitem__(PyObject key) with the + * appropriate args. The only reason to override this method is for performance. * - * @param key the key who will be removed - - * must be an interned string . - * @exception Py.KeyError if the key is not found in the container + * @param key the key who will be removed - must be an interned string . + * @throws PyException {@code KeyError} if the key is not found in the container * * @see #__delitem__(PyObject) **/ @@ -834,27 +786,17 @@ public void __delitem__(String key) { __delitem__(new PyString(key)); } - public PyObject __getslice__( - PyObject s_start, - PyObject s_stop, - PyObject s_step) { + public PyObject __getslice__(PyObject s_start, PyObject s_stop, PyObject s_step) { PySlice s = new PySlice(s_start, s_stop, s_step); return __getitem__(s); } - public void __setslice__( - PyObject s_start, - PyObject s_stop, - PyObject s_step, - PyObject value) { + public void __setslice__(PyObject s_start, PyObject s_stop, PyObject s_step, PyObject value) { PySlice s = new PySlice(s_start, s_stop, s_step); __setitem__(s, value); } - public void __delslice__( - PyObject s_start, - PyObject s_stop, - PyObject s_step) { + public void __delslice__(PyObject s_start, PyObject s_stop, PyObject s_step) { PySlice s = new PySlice(s_start, s_stop, s_step); __delitem__(s); } @@ -871,34 +813,29 @@ public void __delslice__(PyObject start, PyObject stop) { __delslice__(start, stop, null); } - /*The basic functions to implement an iterator */ + /* The basic functions to implement an iterator */ /** * Return an iterator that is used to iterate the element of this sequence. From version 2.2, * this method is the primary protocol for looping over sequences. *

    * If a PyObject subclass should support iteration based in the __finditem__() method, it must - * supply an implementation of __iter__() like this: - * - *

    +     * supply an implementation of __iter__() like this: 
          * public PyObject __iter__() {
          *     return new PySequenceIter(this);
          * }
    -     * 
    - * - * When iterating over a python sequence from java code, it should be done with code like this: - * - *
    +     * 
    When iterating over a python sequence from java code, it should be done with code like + * this:
          * for (PyObject item : seq.asIterable()) {
    -     *     // Do somting with item
    +     *     // Do something with item
          * }
          * 
    * * @since 2.2 */ public PyObject __iter__() { - throw Py.TypeError(String.format("'%.200s' object is not iterable", - getType().fastGetName())); + throw Py.TypeError( + String.format("'%.200s' object is not iterable", getType().fastGetName())); } /** @@ -908,8 +845,12 @@ public PyObject __iter__() { */ public Iterable asIterable() { return new Iterable() { + + @Override public Iterator iterator() { return new WrappedIterIterator(__iter__()) { + + @Override public PyObject next() { return getNext(); } @@ -919,8 +860,8 @@ public PyObject next() { } /** - * Return the next element of the sequence that this is an iterator - * for. Returns null when the end of the sequence is reached. + * Return the next element of the sequence that this is an iterator for. Returns null when the + * end of the sequence is reached. * * @since 2.2 */ @@ -928,16 +869,14 @@ public PyObject __iternext__() { return null; } - /*The basic functions to implement a namespace*/ + /* The basic functions to implement a namespace */ /** - * Very similar to the standard Python __getattr__ method. Instead of - * throwing a AttributeError if the item isn't found, this just returns - * null. + * Very similar to the standard Python __getattr__ method. Instead of throwing a AttributeError + * if the item isn't found, this just returns null. * - * By default, this method will call - * __findattr__(name.internedString) with the appropriate - * args. + * By default, this method will call __findattr__(name.internedString) with the + * appropriate args. * * @param name the name to lookup in this namespace * @@ -951,18 +890,16 @@ public final PyObject __findattr__(PyString name) { } /** - * A variant of the __findattr__ method which accepts a Java - * String as the name. + * A variant of the __findattr__ method which accepts a Java String as the name. * * Warning: name must be an interned string! * - * @param name the name to lookup in this namespace - * must be an interned string . + * @param name the name to lookup in this namespace must be an interned string. * @return the value corresponding to name or null if name is not found **/ public final PyObject __findattr__(String name) { try { - return __findattr_ex__(name); + return __findattr_ex__(name); } catch (PyException exc) { if (exc.match(Py.AttributeError)) { return null; @@ -972,18 +909,17 @@ public final PyObject __findattr__(String name) { } /** - * Attribute lookup hook. If the attribute is not found, null may be - * returned or a Py.AttributeError can be thrown, whatever is more - * correct, efficient and/or convenient for the implementing class. + * Attribute lookup hook. If the attribute is not found, null may be returned or a + * Py.AttributeError can be thrown, whatever is more correct, efficient and/or convenient for + * the implementing class. * - * Client code should use {@link #__getattr__(String)} or - * {@link #__findattr__(String)}. Both methods have a clear policy for - * failed lookups. + * Client code should use {@link #__getattr__(String)} or {@link #__findattr__(String)}. Both + * methods have a clear policy for failed lookups. * * @return The looked up value. May return null if the attribute is not found - * @throws PyException(AttributeError) if the attribute is not found. This - * is not mandatory, null can be returned if it fits the implementation - * better, or for performance reasons. + * @throws PyException {@code AttributeError} if the attribute is not found. This is not + * mandatory, null can be returned if it fits the implementation better, or for + * performance reasons. */ public PyObject __findattr_ex__(String name) { return object___findattr__(name); @@ -992,13 +928,12 @@ public PyObject __findattr_ex__(String name) { /** * Equivalent to the standard Python __getattr__ method. * - * By default, this method will call - * __getattr__(name.internedString) with the appropriate - * args. + * By default, this method will call __getattr__(name.internedString) with the + * appropriate args. * * @param name the name to lookup in this namespace * @return the value corresponding to name - * @exception Py.AttributeError if the name is not found. + * @throws PyException {@code AttributeError} if the name is not found. * * @see #__findattr_ex__(String) **/ @@ -1007,30 +942,28 @@ public final PyObject __getattr__(PyString name) { } /** - * A variant of the __getattr__ method which accepts a Java - * String as the name. - * This method can not be overridden. - * Override the __findattr_ex__ method instead. + * A variant of the __getattr__ method which accepts a Java String as the name. + * This method can not be overridden. Override the __findattr_ex__ method instead. * * Warning: name must be an interned string!!!!!!!! * - * @param name the name to lookup in this namespace - * must be an interned string . + * @param name the name to lookup in this namespace must be an interned string . * @return the value corresponding to name - * @exception Py.AttributeError if the name is not found. + * @throws PyException {@code AttributeError} if the name is not found. * * @see #__findattr__(java.lang.String) **/ public final PyObject __getattr__(String name) { PyObject ret = __findattr_ex__(name); - if (ret == null) + if (ret == null) { noAttributeError(name); + } return ret; } public void noAttributeError(String name) { throw Py.AttributeError(String.format("'%.50s' object has no attribute '%.400s'", - getType().fastGetName(), name)); + getType().fastGetName(), name)); } public void readonlyAttributeError(String name) { @@ -1041,11 +974,10 @@ public void readonlyAttributeError(String name) { } /** - * Equivalent to the standard Python __setattr__ method. - * This method can not be overridden. + * Equivalent to the standard Python __setattr__ method. This method can not be overridden. * * @param name the name to lookup in this namespace - * @exception Py.AttributeError if the name is not found. + * @throws PyException {@code AttributeError} if the name is not found. * * @see #__setattr__(java.lang.String, PyObject) **/ @@ -1054,25 +986,23 @@ public final void __setattr__(PyString name, PyObject value) { } /** - * A variant of the __setattr__ method which accepts a String - * as the key. This String must be interned. + * A variant of the __setattr__ method which accepts a String as the key. This String must be + * interned. * - * @param name the name whose value will be set - - * must be an interned string . + * @param name the name whose value will be set - must be an interned string . * @param value the value to set this name to * * @see #__setattr__(PyString, PyObject) - **/ + **/ public void __setattr__(String name, PyObject value) { object___setattr__(name, value); } /** - * Equivalent to the standard Python __delattr__ method. - * This method can not be overridden. + * Equivalent to the standard Python __delattr__ method. This method can not be overridden. * * @param name the name to which will be removed - * @exception Py.AttributeError if the name doesn't exist + * @throws PyException {@code AttributeError} if the name doesn't exist * * @see #__delattr__(java.lang.String) **/ @@ -1081,16 +1011,12 @@ public final void __delattr__(PyString name) { } /** - * A variant of the __delattr__ method which accepts a String - * as the key. This String must be interned. - * By default, this will call - * __delattr__(PyString name) - * with the appropriate args. - * The only reason to override this method is for performance. + * A variant of the __delattr__ method which accepts a String as the key. This String must be + * interned. By default, this will call __delattr__(PyString name) with the + * appropriate args. The only reason to override this method is for performance. * - * @param name the name which will be removed - - * must be an interned string . - * @exception Py.AttributeError if the name doesn't exist + * @param name the name which will be removed - must be an interned string . + * @throws PyException {@code AttributeError} if the name doesn't exist * * @see #__delattr__(PyString) **/ @@ -1098,7 +1024,13 @@ public void __delattr__(String name) { object___delattr__(name); } - // Used by import logic. + /** + * This is a hook called during the import mechanism when the target module is (or may be) a + * sub-module of this object. + * + * @param name relative to this object must be an interned string. + * @return corresponding value (a module or package) or {@code null} if not found + */ protected PyObject impAttr(String name) { return __findattr__(name); } @@ -1120,8 +1052,7 @@ protected void mergeDictAttr(PyDictionary accum, String attr) { if (obj == null) { return; } - if (obj instanceof PyDictionary || obj instanceof PyStringMap - || obj instanceof PyDictProxy) { + if (obj instanceof AbstractDict || obj instanceof PyDictProxy) { accum.update(obj); } } @@ -1188,10 +1119,9 @@ boolean jdontdel() { * Implements numeric coercion * * @param o the other object involved in the coercion - * @return null if coercion is not implemented - * Py.None if coercion was not possible - * a single PyObject to use to replace o if this is unchanged; - * or a PyObject[2] consisting of replacements for this and o. + * @return null if coercion is not implemented Py.None if coercion was not possible a single + * PyObject to use to replace o if this is unchanged; or a PyObject[2] consisting of + * replacements for this and o. **/ public Object __coerce_ex__(PyObject o) { return null; @@ -1199,29 +1129,29 @@ public Object __coerce_ex__(PyObject o) { /** * Implements coerce(this,other), result as PyObject[] + * * @param other * @return PyObject[] */ PyObject[] _coerce(PyObject other) { Object result; - if (this.getType() == other.getType() && - !(this instanceof PyInstance)) { + if (this.getType() == other.getType() && !(this instanceof PyInstance)) { return new PyObject[] {this, other}; } result = this.__coerce_ex__(other); if (result != null && result != Py.None) { if (result instanceof PyObject[]) { - return (PyObject[])result; + return (PyObject[]) result; } else { - return new PyObject[] {this, (PyObject)result}; + return new PyObject[] {this, (PyObject) result}; } } result = other.__coerce_ex__(this); if (result != null && result != Py.None) { if (result instanceof PyObject[]) { - return (PyObject[])result; + return (PyObject[]) result; } else { - return new PyObject[] {(PyObject)result, other}; + return new PyObject[] {(PyObject) result, other}; } } return null; @@ -1231,16 +1161,15 @@ PyObject[] _coerce(PyObject other) { /** * Equivalent to the standard Python __coerce__ method. * - * This method can not be overridden. - * To implement __coerce__ functionality, override __coerce_ex__ instead. + * This method can not be overridden. To implement __coerce__ functionality, override + * __coerce_ex__ instead. * - * Also, do not call this method from exposed 'coerce' methods. - * Instead, Use adaptToCoerceTuple over the result of the overriden - * __coerce_ex__. + * Also, do not call this method from exposed 'coerce' methods. Instead, Use + * adaptToCoerceTuple over the result of the overridden __coerce_ex__. * * @param pyo the other object involved in the coercion. - * @return a tuple of this object and pyo coerced to the same type - * or Py.NotImplemented if no coercion is possible. + * @return a tuple of this object and pyo coerced to the same type or Py.NotImplemented if no + * coercion is possible. * @see org.python.core.PyObject#__coerce_ex__(org.python.core.PyObject) **/ public final PyObject __coerce__(PyObject pyo) { @@ -1252,15 +1181,14 @@ public final PyObject __coerce__(PyObject pyo) { } /** - * Adapts the result of __coerce_ex__ to a tuple of two elements, with the - * resulting coerced values, or to Py.NotImplemented, if o is Py.None. + * Adapts the result of __coerce_ex__ to a tuple of two elements, with the resulting coerced + * values, or to Py.NotImplemented, if o is Py.None. * - * This is safe to be used from subclasses exposing '__coerce__' - * (as opposed to {@link #__coerce__(PyObject)}, which calls the virtual - * method {@link #__coerce_ex__(PyObject)}) + * This is safe to be used from subclasses exposing '__coerce__' (as opposed to + * {@link #__coerce__(PyObject)}, which calls the virtual method + * {@link #__coerce_ex__(PyObject)}) * - * @param o either a PyObject[2] or a PyObject, as given by - * {@link #__coerce_ex__(PyObject)}. + * @param o either a PyObject[2] or a PyObject, as given by {@link #__coerce_ex__(PyObject)}. */ protected final PyObject adaptToCoerceTuple(Object o) { if (o == Py.None) { @@ -1269,7 +1197,7 @@ protected final PyObject adaptToCoerceTuple(Object o) { if (o instanceof PyObject[]) { return new PyTuple((PyObject[]) o); } else { - return new PyTuple(this, (PyObject) o ); + return new PyTuple(this, (PyObject) o); } } @@ -1279,8 +1207,8 @@ protected final PyObject adaptToCoerceTuple(Object o) { * Equivalent to the standard Python __cmp__ method. * * @param other the object to compare this with. - * @return -1 if this < o; 0 if this == o; +1 if this > o; -2 if no - * comparison is implemented + * @return -1 if {@code thiso}; -2 if no comparison + * is implemented **/ public int __cmp__(PyObject other) { return -2; @@ -1350,7 +1278,7 @@ public PyObject __gt__(PyObject other) { * Implements cmp(this, other) * * @param o the object to compare this with. - * @return -1 if this < 0; 0 if this == o; +1 if this > o + * @return -1 if {@code this<0}; 0 if {@code this==o}; +1 if {@code this>o} **/ public final int _cmp(PyObject o) { if (this == o) { @@ -1361,8 +1289,9 @@ public final int _cmp(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 500) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { return 0; + } } PyObject result; @@ -1398,16 +1327,18 @@ public final int _cmp(PyObject o) { } private PyObject make_pair(PyObject o) { - if (System.identityHashCode(this) < System.identityHashCode(o)) - return new PyIdentityTuple(new PyObject[] { this, o }); - else - return new PyIdentityTuple(new PyObject[] { o, this }); + if (System.identityHashCode(this) < System.identityHashCode(o)) { + return new PyIdentityTuple(new PyObject[] {this, o}); + } else { + return new PyIdentityTuple(new PyObject[] {o, this}); + } } private final int _default_cmp(PyObject other) { int result; - if (_is(other).__nonzero__()) + if (_is(other).__nonzero__()) { return 0; + } /* None is smaller than anything */ if (this == Py.None) { @@ -1444,8 +1375,7 @@ private final int _cmp_unsafe(PyObject other) { } /* - * Like _cmp_unsafe but limited to ==/!= as 0/!=0, - * thus it avoids to invoke _default_cmp. + * Like _cmp_unsafe but limited to ==/!= as 0/!=0, thus it avoids to invoke _default_cmp. */ private final int _cmpeq_unsafe(PyObject other) { int result = _try__cmp__(other); @@ -1453,28 +1383,32 @@ private final int _cmpeq_unsafe(PyObject other) { return result; } - return this._is(other).__nonzero__()?0:1; + return this._is(other).__nonzero__() ? 0 : 1; } /** - * Tries a 3-way comparison, using __cmp__. It tries the following - * operations until one of them succeed:
      - *
    • this.__cmp__(other) - *
    • other.__cmp__(this) - *
    • this._coerce(other) followed by coerced_this.__cmp__(coerced_other)
    + * Tries a 3-way comparison, using __cmp__. It tries the following operations until one of them + * succeed: + *
      + *
    • this.__cmp__(other) + *
    • other.__cmp__(this) + *
    • this._coerce(other) followed by coerced_this.__cmp__(coerced_other) + *
    * * @return -1, 0, -1 or -2, according to the {@link #__cmp__} protocol. */ private int _try__cmp__(PyObject other) { int result; result = this.__cmp__(other); - if (result != -2) + if (result != -2) { return result; + } if (!(this instanceof PyInstance)) { result = other.__cmp__(this); - if (result != -2) + if (result != -2) { return -result; + } } // Final attempt: coerce both arguments and compare that. We are doing // this the same point where CPython 2.5 does. (See @@ -1495,33 +1429,30 @@ private int _try__cmp__(PyObject other) { return -2; } - - - private final static PyObject check_recursion( - ThreadState ts, - PyObject o1, - PyObject o2) { + private final static PyObject check_recursion(ThreadState ts, PyObject o1, PyObject o2) { PyDictionary stateDict = ts.getCompareStateDict(); PyObject pair = o1.make_pair(o2); - if (stateDict.__finditem__(pair) != null) + if (stateDict.__finditem__(pair) != null) { return null; + } stateDict.__setitem__(pair, pair); return pair; } private final static void delete_token(ThreadState ts, PyObject token) { - if (token == null) + if (token == null) { return; + } PyDictionary stateDict = ts.getCompareStateDict(); stateDict.__delitem__(token); } /** - * Implements the Python expression this == other. + * Implements the Python expression {@code this == other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1538,15 +1469,18 @@ public final PyObject _eq(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { return Py.True; + } } PyObject res = __eq__(o); - if (res != null) + if (res != null) { return res; + } res = o.__eq__(this); - if (res != null) + if (res != null) { return res; + } return _cmpeq_unsafe(o) == 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1555,7 +1489,7 @@ public final PyObject _eq(PyObject o) { } /** - * Implements the Python expression this != other. + * Implements the Python expression {@code this != other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1572,15 +1506,18 @@ public final PyObject _ne(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { return Py.False; + } } PyObject res = __ne__(o); - if (res != null) + if (res != null) { return res; + } res = o.__ne__(this); - if (res != null) + if (res != null) { return res; + } return _cmpeq_unsafe(o) != 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1589,7 +1526,7 @@ public final PyObject _ne(PyObject o) { } /** - * Implements the Python expression this <= other. + * Implements the Python expression {@code this <= other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1606,15 +1543,18 @@ public final PyObject _le(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { throw Py.ValueError("can't order recursive values"); + } } PyObject res = __le__(o); - if (res != null) + if (res != null) { return res; + } res = o.__ge__(this); - if (res != null) + if (res != null) { return res; + } return _cmp_unsafe(o) <= 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1623,7 +1563,7 @@ public final PyObject _le(PyObject o) { } /** - * Implements the Python expression this < other. + * Implements the Python expression {@code this < other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1640,15 +1580,18 @@ public final PyObject _lt(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { throw Py.ValueError("can't order recursive values"); + } } PyObject res = __lt__(o); - if (res != null) + if (res != null) { return res; + } res = o.__gt__(this); - if (res != null) + if (res != null) { return res; + } return _cmp_unsafe(o) < 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1657,7 +1600,7 @@ public final PyObject _lt(PyObject o) { } /** - * Implements the Python expression this >= other. + * Implements the Python expression {@code this >= other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1674,15 +1617,18 @@ public final PyObject _ge(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { throw Py.ValueError("can't order recursive values"); + } } PyObject res = __ge__(o); - if (res != null) + if (res != null) { return res; + } res = o.__le__(this); - if (res != null) + if (res != null) { return res; + } return _cmp_unsafe(o) >= 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1691,7 +1637,7 @@ public final PyObject _ge(PyObject o) { } /** - * Implements the Python expression this > other. + * Implements the Python expression {@code this > other}. * * @param o the object to compare this with. * @return the result of the comparison @@ -1708,15 +1654,18 @@ public final PyObject _gt(PyObject o) { ThreadState ts = Py.getThreadState(); try { if (++ts.compareStateNesting > 10) { - if ((token = check_recursion(ts, this, o)) == null) + if ((token = check_recursion(ts, this, o)) == null) { throw Py.ValueError("can't order recursive values"); + } } PyObject res = __gt__(o); - if (res != null) + if (res != null) { return res; + } res = o.__lt__(this); - if (res != null) + if (res != null) { return res; + } return _cmp_unsafe(o) > 0 ? Py.True : Py.False; } finally { delete_token(ts, token); @@ -1734,9 +1683,9 @@ public final PyObject _gt(PyObject o) { public PyObject _is(PyObject o) { // Access javaProxy directly here as is is for object identity, and at best getJavaProxy // will initialize a new object with a different identity - return this == o || (JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) && - JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) == - JyAttribute.getAttr(o, JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False; + return this == o || (JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) + && JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) == JyAttribute.getAttr(o, + JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False; } /** @@ -1748,9 +1697,9 @@ public PyObject _is(PyObject o) { public PyObject _isnot(PyObject o) { // Access javaProxy directly here as is is for object identity, and at best getJavaProxy // will initialize a new object with a different identity - return this != o && (!JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) || - JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) != - JyAttribute.getAttr(o, JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False; + return this != o && (!JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) + || JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR) != JyAttribute.getAttr(o, + JyAttribute.JAVA_PROXY_ATTR)) ? Py.True : Py.False; } /** @@ -1798,8 +1747,10 @@ public PyObject __format__(PyObject formatSpec) { @ExposedMethod(doc = BuiltinDocs.object___format___doc) final PyObject object___format__(PyObject formatSpec) { - if (formatSpec != null && formatSpec instanceof PyString && !((PyString)formatSpec).getString().isEmpty()) { - Py.warning(Py.PendingDeprecationWarning, "object.__format__ with a non-empty format string is deprecated"); + if (formatSpec != null && formatSpec instanceof PyString + && !((PyString) formatSpec).getString().isEmpty()) { + Py.warning(Py.PendingDeprecationWarning, + "object.__format__ with a non-empty format string is deprecated"); } return __str__().__format__(formatSpec); } @@ -1816,9 +1767,8 @@ public PyObject __not__() { /* The basic numeric operations */ /** - * Equivalent to the standard Python __hex__ method - * Should only be overridden by numeric objects that can be - * reasonably represented as a hexadecimal string. + * Equivalent to the standard Python __hex__ method Should only be overridden by numeric objects + * that can be reasonably represented as a hexadecimal string. * * @return a string representing this object as a hexadecimal number. **/ @@ -1827,9 +1777,8 @@ public PyString __hex__() { } /** - * Equivalent to the standard Python __oct__ method. - * Should only be overridden by numeric objects that can be - * reasonably represented as an octal string. + * Equivalent to the standard Python __oct__ method. Should only be overridden by numeric + * objects that can be reasonably represented as an octal string. * * @return a string representing this object as an octal number. **/ @@ -1838,9 +1787,8 @@ public PyString __oct__() { } /** - * Equivalent to the standard Python __int__ method. - * Should only be overridden by numeric objects that can be - * reasonably coerced into an integer. + * Equivalent to the standard Python __int__ method. Should only be overridden by numeric + * objects that can be reasonably coerced into an integer. * * @return an integer corresponding to the value of this object. **/ @@ -1849,9 +1797,8 @@ public PyObject __int__() { } /** - * Equivalent to the standard Python __long__ method. - * Should only be overridden by numeric objects that can be - * reasonably coerced into a python long. + * Equivalent to the standard Python __long__ method. Should only be overridden by numeric + * objects that can be reasonably coerced into a python long. * * @return a PyLong or PyInteger corresponding to the value of this object. **/ @@ -1860,9 +1807,8 @@ public PyObject __long__() { } /** - * Equivalent to the standard Python __float__ method. - * Should only be overridden by numeric objects that can be - * reasonably coerced into a python float. + * Equivalent to the standard Python __float__ method. Should only be overridden by numeric + * objects that can be reasonably coerced into a python float. * * @return a float corresponding to the value of this object. **/ @@ -1871,9 +1817,8 @@ public PyFloat __float__() { } /** - * Equivalent to the standard Python __complex__ method. - * Should only be overridden by numeric objects that can be - * reasonably coerced into a python complex number. + * Equivalent to the standard Python __complex__ method. Should only be overridden by numeric + * objects that can be reasonably coerced into a python complex number. * * @return a complex number corresponding to the value of this object. **/ @@ -1882,9 +1827,8 @@ public PyComplex __complex__() { } /** - * Equivalent to the standard Python __trunc__ method. - * Should only be overridden by numeric objects that can reasonably - * be truncated to an Integral. + * Equivalent to the standard Python __trunc__ method. Should only be overridden by numeric + * objects that can reasonably be truncated to an Integral. * * @return the Integral closest to x between 0 and x. **/ @@ -1893,9 +1837,8 @@ public PyObject __trunc__() { } /** - * Equivalent to the standard Python conjugate method. - * Should only be overridden by numeric objects that can calculate a - * complex conjugate. + * Equivalent to the standard Python conjugate method. Should only be overridden by numeric + * objects that can calculate a complex conjugate. * * @return the complex conjugate. **/ @@ -1904,9 +1847,8 @@ public PyObject conjugate() { } /** - * Equivalent to the standard Python bit_length method. - * Should only be overridden by numeric objects that can calculate a - * bit_length. + * Equivalent to the standard Python bit_length method. Should only be overridden by numeric + * objects that can calculate a bit_length. * * @return the bit_length of this object. **/ @@ -1920,8 +1862,8 @@ public int bit_length() { * @return +this. **/ public PyObject __pos__() { - throw Py.TypeError(String.format("bad operand type for unary +: '%.200s'", - getType().fastGetName())); + throw Py.TypeError( + String.format("bad operand type for unary +: '%.200s'", getType().fastGetName())); } /** @@ -1930,8 +1872,8 @@ public PyObject __pos__() { * @return -this. **/ public PyObject __neg__() { - throw Py.TypeError(String.format("bad operand type for unary -: '%.200s'", - getType().fastGetName())); + throw Py.TypeError( + String.format("bad operand type for unary -: '%.200s'", getType().fastGetName())); } /** @@ -1940,8 +1882,8 @@ public PyObject __neg__() { * @return abs(this). **/ public PyObject __abs__() { - throw Py.TypeError(String.format("bad operand type for abs(): '%.200s'", - getType().fastGetName())); + throw Py.TypeError( + String.format("bad operand type for abs(): '%.200s'", getType().fastGetName())); } /** @@ -1950,19 +1892,19 @@ public PyObject __abs__() { * @return ~this. **/ public PyObject __invert__() { - throw Py.TypeError(String.format("bad operand type for unary ~: '%.200s'", - getType().fastGetName())); + throw Py.TypeError( + String.format("bad operand type for unary ~: '%.200s'", getType().fastGetName())); } /** * Equivalent to the standard Python __index__ method. * * @return a PyInteger or PyLong - * @throws a Py.TypeError if not supported + * @throws PyException {@code TypeError} if not supported **/ public PyObject __index__() { throw Py.TypeError(String.format("'%.200s' object cannot be interpreted as an index", - getType().fastGetName())); + getType().fastGetName())); } /** @@ -1984,9 +1926,7 @@ protected final String _unsupportedop(String op, PyObject o2) { /** * Should return an error message suitable for substitution where. * - * {0} is the op name. - * {1} is the left operand type. - * {2} is the right operand type. + * {0} is the op name. {1} is the left operand type. {2} is the right operand type. */ protected String unsupportedopMessage(String op, PyObject o2) { return null; @@ -1995,9 +1935,7 @@ protected String unsupportedopMessage(String op, PyObject o2) { /** * Should return an error message suitable for substitution where. * - * {0} is the op name. - * {1} is the left operand type. - * {2} is the right operand type. + * {0} is the op name. {1} is the left operand type. {2} is the right operand type. */ protected String runsupportedopMessage(String op, PyObject o2) { return null; @@ -2007,8 +1945,7 @@ protected String runsupportedopMessage(String op, PyObject o2) { * Implements the three argument power function. * * @param o2 the power to raise this number to. - * @param o3 the modulus to perform this operation in or null if no - * modulo is to be used + * @param o3 the modulus to perform this operation in or null if no modulo is to be used * @return this object raised to the given power in the given modulus **/ public PyObject __pow__(PyObject o2, PyObject o3) { @@ -2016,15 +1953,13 @@ public PyObject __pow__(PyObject o2, PyObject o3) { } /** - * Determine if the binary op on types t1 and t2 is an add - * operation dealing with a str/unicode and a str/unicode - * subclass. + * Determine if the binary op on types t1 and t2 is an add operation dealing with a str/unicode + * and a str/unicode subclass. * - * This operation is special cased in _binop_rule to match - * CPython's handling; CPython uses tp_as_number and - * tp_as_sequence to allow string/unicode subclasses to override - * the left side's __add__ when that left side is an actual str or - * unicode object (see test_concat_jy for examples). + * This operation is special cased in _binop_rule to match CPython's handling; CPython uses + * tp_as_number and tp_as_sequence to allow string/unicode subclasses to override the left + * side's __add__ when that left side is an actual str or unicode object (see test_concat_jy for + * examples). * * @param t1 left side PyType * @param t2 right side PyType @@ -2036,20 +1971,18 @@ private boolean isStrUnicodeSpecialCase(PyType t1, PyType t2, String op) { // situations // XXX: This method isn't expensive but could (and maybe // should?) be optimized for worst case scenarios - return (op == "+") && (t1 == PyString.TYPE || t1 == PyUnicode.TYPE) && - (t2.isSubType(PyString.TYPE) || t2.isSubType(PyUnicode.TYPE)); + return (op == "+") && (t1 == PyString.TYPE || t1 == PyUnicode.TYPE) + && (t2.isSubType(PyString.TYPE) || t2.isSubType(PyUnicode.TYPE)); } - private PyObject _binop_rule(PyType t1, PyObject o2, PyType t2, - String left, String right, String op) { + private PyObject _binop_rule(PyType t1, PyObject o2, PyType t2, String left, String right, + String op) { /* - * this is the general rule for binary operation dispatching try first - * __xxx__ with this and then __rxxx__ with o2 unless o2 is an instance - * of subclass of the type of this, and further __xxx__ and __rxxx__ are - * unrelated ( checked here by looking at where in the hierarchy they - * are defined), in that case try them in the reverse order. This is the - * same formulation as used by PyPy, see also - * test_descr.subclass_right_op. + * this is the general rule for binary operation dispatching try first __xxx__ with this and + * then __rxxx__ with o2 unless o2 is an instance of subclass of the type of this, and + * further __xxx__ and __rxxx__ are unrelated ( checked here by looking at where in the + * hierarchy they are defined), in that case try them in the reverse order. This is the same + * formulation as used by PyPy, see also test_descr.subclass_right_op. */ PyObject o1 = this; PyObject[] where = new PyObject[1]; @@ -2058,10 +1991,9 @@ private PyObject _binop_rule(PyType t1, PyObject o2, PyType t2, where1 = where[0]; PyObject impl2 = t2.lookup_where(right, where); where2 = where[0]; - if (impl2 != null && impl1 != null && where1 != where2 && - (t2.isSubType(t1) && !Py.isSubClass(where1, where2) - && !Py.isSubClass(t1, where2) || - isStrUnicodeSpecialCase(t1, t2, op))) { + if (impl2 != null && impl1 != null && where1 != where2 + && (t2.isSubType(t1) && !Py.isSubClass(where1, where2) && !Py.isSubClass(t1, where2) + || isStrUnicodeSpecialCase(t1, t2, op))) { PyObject tmp = o1; o1 = o2; o2 = tmp; @@ -2093,10 +2025,9 @@ private PyObject _binop_rule(PyType t1, PyObject o2, PyType t2, /** * Equivalent to the standard Python __add__ method. - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the add, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the add, or null if this operation is not defined. **/ public PyObject __add__(PyObject other) { return null; @@ -2104,10 +2035,9 @@ public PyObject __add__(PyObject other) { /** * Equivalent to the standard Python __radd__ method. - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the add, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the add, or null if this operation is not defined. **/ public PyObject __radd__(PyObject other) { return null; @@ -2115,87 +2045,88 @@ public PyObject __radd__(PyObject other) { /** * Equivalent to the standard Python __iadd__ method. - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the iadd, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the iadd, or null if this operation is not defined **/ public PyObject __iadd__(PyObject other) { return null; } /** - * Implements the Python expression this + o2. - * @param o2 the object to perform this binary operation with. - * @return the result of the add. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this + o2}. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the add. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _add(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_add(o2); } - return _binop_rule(t1,o2,t2,"__add__","__radd__","+"); + return _binop_rule(t1, o2, t2, "__add__", "__radd__", "+"); } /** - * Implements the Python expression this + o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the add. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this + o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the add. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_add(PyObject o2) { - PyObject x=__add__(o2); - if (x!=null) { + PyObject x = __add__(o2); + if (x != null) { return x; } - x=o2.__radd__(this); - if (x!=null) { + x = o2.__radd__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("+",o2)); + throw Py.TypeError(_unsupportedop("+", o2)); } /** - * Implements the Python expression this += o2. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the iadd. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this += o2}. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the iadd. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _iadd(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_iadd(o2); } - PyObject impl=t1.lookup("__iadd__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__iadd__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__add__","__radd__","+"); + return _binop_rule(t1, o2, t2, "__add__", "__radd__", "+"); } /** - * Implements the Python expression this += o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the iadd. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this += o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the iadd. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_iadd(PyObject o2) { - PyObject x=__iadd__(o2); - if (x!=null) { + PyObject x = __iadd__(o2); + if (x != null) { return x; } return this._basic_add(o2); @@ -2203,10 +2134,9 @@ final PyObject _basic_iadd(PyObject o2) { /** * Equivalent to the standard Python __sub__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the sub, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the sub, or null if this operation is not defined **/ public PyObject __sub__(PyObject other) { return null; @@ -2214,10 +2144,9 @@ public PyObject __sub__(PyObject other) { /** * Equivalent to the standard Python __rsub__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the sub, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the sub, or null if this operation is not defined. **/ public PyObject __rsub__(PyObject other) { return null; @@ -2225,87 +2154,88 @@ public PyObject __rsub__(PyObject other) { /** * Equivalent to the standard Python __isub__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the isub, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the isub, or null if this operation is not defined **/ public PyObject __isub__(PyObject other) { return null; } /** - * Implements the Python expression this - o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the sub. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this - o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the sub. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _sub(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_sub(o2); } - return _binop_rule(t1,o2,t2,"__sub__","__rsub__","-"); + return _binop_rule(t1, o2, t2, "__sub__", "__rsub__", "-"); } /** - * Implements the Python expression this - o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the sub. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this - o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the sub. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_sub(PyObject o2) { - PyObject x=__sub__(o2); - if (x!=null) { + PyObject x = __sub__(o2); + if (x != null) { return x; } - x=o2.__rsub__(this); - if (x!=null) { + x = o2.__rsub__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("-",o2)); + throw Py.TypeError(_unsupportedop("-", o2)); } /** - * Implements the Python expression this -= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the isub. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this -= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the isub. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _isub(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_isub(o2); } - PyObject impl=t1.lookup("__isub__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__isub__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__sub__","__rsub__","-"); + return _binop_rule(t1, o2, t2, "__sub__", "__rsub__", "-"); } /** - * Implements the Python expression this -= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the isub. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this -= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the isub. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_isub(PyObject o2) { - PyObject x=__isub__(o2); - if (x!=null) { + PyObject x = __isub__(o2); + if (x != null) { return x; } return this._basic_sub(o2); @@ -2313,10 +2243,9 @@ final PyObject _basic_isub(PyObject o2) { /** * Equivalent to the standard Python __mul__ method. - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the mul, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the mul, or null if this operation is not defined **/ public PyObject __mul__(PyObject other) { return null; @@ -2324,10 +2253,9 @@ public PyObject __mul__(PyObject other) { /** * Equivalent to the standard Python __rmul__ method. - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the mul, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the mul, or null if this operation is not defined. **/ public PyObject __rmul__(PyObject other) { return null; @@ -2335,87 +2263,88 @@ public PyObject __rmul__(PyObject other) { /** * Equivalent to the standard Python __imul__ method. - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the imul, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the imul, or null if this operation is not defined. **/ public PyObject __imul__(PyObject other) { return null; } /** - * Implements the Python expression this * o2. - * @param o2 the object to perform this binary operation with. - * @return the result of the mul. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this * o2}. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the mul. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _mul(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_mul(o2); } - return _binop_rule(t1,o2,t2,"__mul__","__rmul__","*"); + return _binop_rule(t1, o2, t2, "__mul__", "__rmul__", "*"); } /** - * Implements the Python expression this * o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the mul. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this * o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the mul. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_mul(PyObject o2) { - PyObject x=__mul__(o2); - if (x!=null) { + PyObject x = __mul__(o2); + if (x != null) { return x; } - x=o2.__rmul__(this); - if (x!=null) { + x = o2.__rmul__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("*",o2)); + throw Py.TypeError(_unsupportedop("*", o2)); } /** - * Implements the Python expression this *= o2. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the imul. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this *= o2}. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the imul. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _imul(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_imul(o2); } - PyObject impl=t1.lookup("__imul__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__imul__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__mul__","__rmul__","*"); + return _binop_rule(t1, o2, t2, "__mul__", "__rmul__", "*"); } /** - * Implements the Python expression this *= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the imul. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this *= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the imul. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_imul(PyObject o2) { - PyObject x=__imul__(o2); - if (x!=null) { + PyObject x = __imul__(o2); + if (x != null) { return x; } return this._basic_mul(o2); @@ -2423,10 +2352,9 @@ final PyObject _basic_imul(PyObject o2) { /** * Equivalent to the standard Python __div__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the div, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the div, or null if this operation is not defined **/ public PyObject __div__(PyObject other) { return null; @@ -2434,10 +2362,9 @@ public PyObject __div__(PyObject other) { /** * Equivalent to the standard Python __rdiv__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the div, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the div, or null if this operation is not defined. **/ public PyObject __rdiv__(PyObject other) { return null; @@ -2445,91 +2372,94 @@ public PyObject __rdiv__(PyObject other) { /** * Equivalent to the standard Python __idiv__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the idiv, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the idiv, or null if this operation is not defined **/ public PyObject __idiv__(PyObject other) { return null; } /** - * Implements the Python expression this / o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the div. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this / o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the div. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _div(PyObject o2) { - if (Options.Qnew) + if (Options.Qnew) { return _truediv(o2); - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + } + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_div(o2); } - return _binop_rule(t1,o2,t2,"__div__","__rdiv__","/"); + return _binop_rule(t1, o2, t2, "__div__", "__rdiv__", "/"); } /** - * Implements the Python expression this / o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the div. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this / o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the div. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_div(PyObject o2) { - PyObject x=__div__(o2); - if (x!=null) { + PyObject x = __div__(o2); + if (x != null) { return x; } - x=o2.__rdiv__(this); - if (x!=null) { + x = o2.__rdiv__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("/",o2)); + throw Py.TypeError(_unsupportedop("/", o2)); } /** - * Implements the Python expression this /= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the idiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this /= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the idiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _idiv(PyObject o2) { - if (Options.Qnew) + if (Options.Qnew) { return _itruediv(o2); - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + } + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_idiv(o2); } - PyObject impl=t1.lookup("__idiv__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__idiv__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__div__","__rdiv__","/"); + return _binop_rule(t1, o2, t2, "__div__", "__rdiv__", "/"); } /** - * Implements the Python expression this /= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the idiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this /= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the idiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_idiv(PyObject o2) { - PyObject x=__idiv__(o2); - if (x!=null) { + PyObject x = __idiv__(o2); + if (x != null) { return x; } return this._basic_div(o2); @@ -2537,10 +2467,9 @@ final PyObject _basic_idiv(PyObject o2) { /** * Equivalent to the standard Python __floordiv__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the floordiv, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the floordiv, or null if this operation is not defined **/ public PyObject __floordiv__(PyObject other) { return null; @@ -2548,10 +2477,9 @@ public PyObject __floordiv__(PyObject other) { /** * Equivalent to the standard Python __rfloordiv__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the floordiv, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the floordiv, or null if this operation is not defined. **/ public PyObject __rfloordiv__(PyObject other) { return null; @@ -2559,87 +2487,88 @@ public PyObject __rfloordiv__(PyObject other) { /** * Equivalent to the standard Python __ifloordiv__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the ifloordiv, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the ifloordiv, or null if this operation is not defined **/ public PyObject __ifloordiv__(PyObject other) { return null; } /** - * Implements the Python expression this // o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the floordiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this // o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the floordiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _floordiv(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_floordiv(o2); } - return _binop_rule(t1,o2,t2,"__floordiv__","__rfloordiv__","//"); + return _binop_rule(t1, o2, t2, "__floordiv__", "__rfloordiv__", "//"); } /** - * Implements the Python expression this // o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the floordiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this // o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the floordiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_floordiv(PyObject o2) { - PyObject x=__floordiv__(o2); - if (x!=null) { + PyObject x = __floordiv__(o2); + if (x != null) { return x; } - x=o2.__rfloordiv__(this); - if (x!=null) { + x = o2.__rfloordiv__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("//",o2)); + throw Py.TypeError(_unsupportedop("//", o2)); } /** - * Implements the Python expression this //= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ifloordiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this //= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ifloordiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _ifloordiv(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_ifloordiv(o2); } - PyObject impl=t1.lookup("__ifloordiv__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__ifloordiv__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__floordiv__","__rfloordiv__","//"); + return _binop_rule(t1, o2, t2, "__floordiv__", "__rfloordiv__", "//"); } /** - * Implements the Python expression this //= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ifloordiv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this //= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ifloordiv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_ifloordiv(PyObject o2) { - PyObject x=__ifloordiv__(o2); - if (x!=null) { + PyObject x = __ifloordiv__(o2); + if (x != null) { return x; } return this._basic_floordiv(o2); @@ -2647,10 +2576,9 @@ final PyObject _basic_ifloordiv(PyObject o2) { /** * Equivalent to the standard Python __truediv__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the truediv, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the truediv, or null if this operation is not defined **/ public PyObject __truediv__(PyObject other) { return null; @@ -2658,10 +2586,9 @@ public PyObject __truediv__(PyObject other) { /** * Equivalent to the standard Python __rtruediv__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the truediv, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the truediv, or null if this operation is not defined. **/ public PyObject __rtruediv__(PyObject other) { return null; @@ -2669,87 +2596,88 @@ public PyObject __rtruediv__(PyObject other) { /** * Equivalent to the standard Python __itruediv__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the itruediv, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the itruediv, or null if this operation is not defined **/ public PyObject __itruediv__(PyObject other) { return null; } /** - * Implements the Python expression this / o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the truediv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this / o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the truediv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _truediv(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_truediv(o2); } - return _binop_rule(t1,o2,t2,"__truediv__","__rtruediv__","/"); + return _binop_rule(t1, o2, t2, "__truediv__", "__rtruediv__", "/"); } /** - * Implements the Python expression this / o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the truediv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this / o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the truediv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_truediv(PyObject o2) { - PyObject x=__truediv__(o2); - if (x!=null) { + PyObject x = __truediv__(o2); + if (x != null) { return x; } - x=o2.__rtruediv__(this); - if (x!=null) { + x = o2.__rtruediv__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("/",o2)); + throw Py.TypeError(_unsupportedop("/", o2)); } /** - * Implements the Python expression this /= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the itruediv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this /= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the itruediv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _itruediv(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_itruediv(o2); } - PyObject impl=t1.lookup("__itruediv__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__itruediv__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__truediv__","__rtruediv__","/"); + return _binop_rule(t1, o2, t2, "__truediv__", "__rtruediv__", "/"); } /** - * Implements the Python expression this /= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the itruediv. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this /= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the itruediv. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_itruediv(PyObject o2) { - PyObject x=__itruediv__(o2); - if (x!=null) { + PyObject x = __itruediv__(o2); + if (x != null) { return x; } return this._basic_truediv(o2); @@ -2757,10 +2685,9 @@ final PyObject _basic_itruediv(PyObject o2) { /** * Equivalent to the standard Python __mod__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the mod, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the mod, or null if this operation is not defined **/ public PyObject __mod__(PyObject other) { return null; @@ -2768,10 +2695,9 @@ public PyObject __mod__(PyObject other) { /** * Equivalent to the standard Python __rmod__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the mod, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the mod, or null if this operation is not defined. **/ public PyObject __rmod__(PyObject other) { return null; @@ -2779,87 +2705,88 @@ public PyObject __rmod__(PyObject other) { /** * Equivalent to the standard Python __imod__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the imod, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the imod, or null if this operation is not defined **/ public PyObject __imod__(PyObject other) { return null; } /** - * Implements the Python expression this % o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the mod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this % o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the mod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _mod(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_mod(o2); } - return _binop_rule(t1,o2,t2,"__mod__","__rmod__","%"); + return _binop_rule(t1, o2, t2, "__mod__", "__rmod__", "%"); } /** - * Implements the Python expression this % o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the mod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this % o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the mod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_mod(PyObject o2) { - PyObject x=__mod__(o2); - if (x!=null) { + PyObject x = __mod__(o2); + if (x != null) { return x; } - x=o2.__rmod__(this); - if (x!=null) { + x = o2.__rmod__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("%",o2)); + throw Py.TypeError(_unsupportedop("%", o2)); } /** - * Implements the Python expression this %= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the imod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this %= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the imod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _imod(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_imod(o2); } - PyObject impl=t1.lookup("__imod__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__imod__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__mod__","__rmod__","%"); + return _binop_rule(t1, o2, t2, "__mod__", "__rmod__", "%"); } /** - * Implements the Python expression this %= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the imod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this %= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the imod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_imod(PyObject o2) { - PyObject x=__imod__(o2); - if (x!=null) { + PyObject x = __imod__(o2); + if (x != null) { return x; } return this._basic_mod(o2); @@ -2867,10 +2794,9 @@ final PyObject _basic_imod(PyObject o2) { /** * Equivalent to the standard Python __divmod__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the divmod, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the divmod, or null if this operation is not defined **/ public PyObject __divmod__(PyObject other) { return null; @@ -2878,10 +2804,9 @@ public PyObject __divmod__(PyObject other) { /** * Equivalent to the standard Python __rdivmod__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the divmod, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the divmod, or null if this operation is not defined. **/ public PyObject __rdivmod__(PyObject other) { return null; @@ -2889,87 +2814,88 @@ public PyObject __rdivmod__(PyObject other) { /** * Equivalent to the standard Python __idivmod__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the idivmod, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the idivmod, or null if this operation is not defined **/ public PyObject __idivmod__(PyObject other) { return null; } /** - * Implements the Python expression this divmod o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the divmod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this divmod o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the divmod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _divmod(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_divmod(o2); } - return _binop_rule(t1,o2,t2,"__divmod__","__rdivmod__","divmod"); + return _binop_rule(t1, o2, t2, "__divmod__", "__rdivmod__", "divmod"); } /** - * Implements the Python expression this divmod o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the divmod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this divmod o2} when this and o2 have the same type + * or are builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the divmod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_divmod(PyObject o2) { - PyObject x=__divmod__(o2); - if (x!=null) { + PyObject x = __divmod__(o2); + if (x != null) { return x; } - x=o2.__rdivmod__(this); - if (x!=null) { + x = o2.__rdivmod__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("divmod",o2)); + throw Py.TypeError(_unsupportedop("divmod", o2)); } /** - * Implements the Python expression this divmod= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the idivmod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this divmod= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the idivmod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _idivmod(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_idivmod(o2); } - PyObject impl=t1.lookup("__idivmod__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__idivmod__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__divmod__","__rdivmod__","divmod"); + return _binop_rule(t1, o2, t2, "__divmod__", "__rdivmod__", "divmod"); } /** - * Implements the Python expression this divmod= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the idivmod. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this divmod= o2} when this and o2 have the same type + * or are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the idivmod. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_idivmod(PyObject o2) { - PyObject x=__idivmod__(o2); - if (x!=null) { + PyObject x = __idivmod__(o2); + if (x != null) { return x; } return this._basic_divmod(o2); @@ -2977,21 +2903,19 @@ final PyObject _basic_idivmod(PyObject o2) { /** * Equivalent to the standard Python __pow__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the pow, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the pow, or null if this operation is not defined **/ public PyObject __pow__(PyObject other) { - return __pow__(other,null); + return __pow__(other, null); } /** * Equivalent to the standard Python __rpow__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the pow, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the pow, or null if this operation is not defined. **/ public PyObject __rpow__(PyObject other) { return null; @@ -2999,87 +2923,88 @@ public PyObject __rpow__(PyObject other) { /** * Equivalent to the standard Python __ipow__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the ipow, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the ipow, or null if this operation is not defined **/ public PyObject __ipow__(PyObject other) { return null; } /** - * Implements the Python expression this ** o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the pow. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this ** o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the pow. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _pow(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_pow(o2); } - return _binop_rule(t1,o2,t2,"__pow__","__rpow__","**"); + return _binop_rule(t1, o2, t2, "__pow__", "__rpow__", "**"); } /** - * Implements the Python expression this ** o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the pow. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this ** o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the pow. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_pow(PyObject o2) { - PyObject x=__pow__(o2); - if (x!=null) { + PyObject x = __pow__(o2); + if (x != null) { return x; } - x=o2.__rpow__(this); - if (x!=null) { + x = o2.__rpow__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("**",o2)); + throw Py.TypeError(_unsupportedop("**", o2)); } /** - * Implements the Python expression this **= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ipow. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this **= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ipow. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _ipow(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_ipow(o2); } - PyObject impl=t1.lookup("__ipow__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__ipow__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__pow__","__rpow__","**"); + return _binop_rule(t1, o2, t2, "__pow__", "__rpow__", "**"); } /** - * Implements the Python expression this **= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ipow. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this **= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ipow. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_ipow(PyObject o2) { - PyObject x=__ipow__(o2); - if (x!=null) { + PyObject x = __ipow__(o2); + if (x != null) { return x; } return this._basic_pow(o2); @@ -3087,10 +3012,9 @@ final PyObject _basic_ipow(PyObject o2) { /** * Equivalent to the standard Python __lshift__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the lshift, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the lshift, or null if this operation is not defined **/ public PyObject __lshift__(PyObject other) { return null; @@ -3098,10 +3022,9 @@ public PyObject __lshift__(PyObject other) { /** * Equivalent to the standard Python __rlshift__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the lshift, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the lshift, or null if this operation is not defined. **/ public PyObject __rlshift__(PyObject other) { return null; @@ -3109,87 +3032,88 @@ public PyObject __rlshift__(PyObject other) { /** * Equivalent to the standard Python __ilshift__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the ilshift, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the ilshift, or null if this operation is not defined **/ public PyObject __ilshift__(PyObject other) { return null; } /** - * Implements the Python expression this << o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the lshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this << o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the lshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _lshift(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_lshift(o2); } - return _binop_rule(t1,o2,t2,"__lshift__","__rlshift__","<<"); + return _binop_rule(t1, o2, t2, "__lshift__", "__rlshift__", "<<"); } /** - * Implements the Python expression this << o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the lshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this << o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the lshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_lshift(PyObject o2) { - PyObject x=__lshift__(o2); - if (x!=null) { + PyObject x = __lshift__(o2); + if (x != null) { return x; } - x=o2.__rlshift__(this); - if (x!=null) { + x = o2.__rlshift__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("<<",o2)); + throw Py.TypeError(_unsupportedop("<<", o2)); } /** - * Implements the Python expression this <<= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ilshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this <<= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ilshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _ilshift(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_ilshift(o2); } - PyObject impl=t1.lookup("__ilshift__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__ilshift__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__lshift__","__rlshift__","<<"); + return _binop_rule(t1, o2, t2, "__lshift__", "__rlshift__", "<<"); } /** - * Implements the Python expression this <<= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ilshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this <<= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ilshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_ilshift(PyObject o2) { - PyObject x=__ilshift__(o2); - if (x!=null) { + PyObject x = __ilshift__(o2); + if (x != null) { return x; } return this._basic_lshift(o2); @@ -3197,10 +3121,9 @@ final PyObject _basic_ilshift(PyObject o2) { /** * Equivalent to the standard Python __rshift__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the rshift, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the rshift, or null if this operation is not defined **/ public PyObject __rshift__(PyObject other) { return null; @@ -3208,10 +3131,9 @@ public PyObject __rshift__(PyObject other) { /** * Equivalent to the standard Python __rrshift__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the rshift, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the rshift, or null if this operation is not defined. **/ public PyObject __rrshift__(PyObject other) { return null; @@ -3219,87 +3141,88 @@ public PyObject __rrshift__(PyObject other) { /** * Equivalent to the standard Python __irshift__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the irshift, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the irshift, or null if this operation is not defined **/ public PyObject __irshift__(PyObject other) { return null; } /** - * Implements the Python expression this >> o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the rshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this >> o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the rshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _rshift(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_rshift(o2); } - return _binop_rule(t1,o2,t2,"__rshift__","__rrshift__",">>"); + return _binop_rule(t1, o2, t2, "__rshift__", "__rrshift__", ">>"); } /** - * Implements the Python expression this >> o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the rshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this >> o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the rshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_rshift(PyObject o2) { - PyObject x=__rshift__(o2); - if (x!=null) { + PyObject x = __rshift__(o2); + if (x != null) { return x; } - x=o2.__rrshift__(this); - if (x!=null) { + x = o2.__rrshift__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop(">>",o2)); + throw Py.TypeError(_unsupportedop(">>", o2)); } /** - * Implements the Python expression this >>= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the irshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this >>= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the irshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _irshift(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_irshift(o2); } - PyObject impl=t1.lookup("__irshift__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__irshift__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__rshift__","__rrshift__",">>"); + return _binop_rule(t1, o2, t2, "__rshift__", "__rrshift__", ">>"); } /** - * Implements the Python expression this >>= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the irshift. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this >>= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the irshift. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_irshift(PyObject o2) { - PyObject x=__irshift__(o2); - if (x!=null) { + PyObject x = __irshift__(o2); + if (x != null) { return x; } return this._basic_rshift(o2); @@ -3307,10 +3230,9 @@ final PyObject _basic_irshift(PyObject o2) { /** * Equivalent to the standard Python __and__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the and, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the and, or null if this operation is not defined **/ public PyObject __and__(PyObject other) { return null; @@ -3318,10 +3240,9 @@ public PyObject __and__(PyObject other) { /** * Equivalent to the standard Python __rand__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the and, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the and, or null if this operation is not defined. **/ public PyObject __rand__(PyObject other) { return null; @@ -3329,87 +3250,88 @@ public PyObject __rand__(PyObject other) { /** * Equivalent to the standard Python __iand__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the iand, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the iand, or null if this operation is not defined **/ public PyObject __iand__(PyObject other) { return null; } /** - * Implements the Python expression this & o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the and. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this & o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the and. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _and(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_and(o2); } - return _binop_rule(t1,o2,t2,"__and__","__rand__","&"); + return _binop_rule(t1, o2, t2, "__and__", "__rand__", "&"); } /** - * Implements the Python expression this & o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the and. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this & o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the and. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_and(PyObject o2) { - PyObject x=__and__(o2); - if (x!=null) { + PyObject x = __and__(o2); + if (x != null) { return x; } - x=o2.__rand__(this); - if (x!=null) { + x = o2.__rand__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("&",o2)); + throw Py.TypeError(_unsupportedop("&", o2)); } /** - * Implements the Python expression this &= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the iand. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this &= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the iand. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _iand(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_iand(o2); } - PyObject impl=t1.lookup("__iand__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__iand__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__and__","__rand__","&"); + return _binop_rule(t1, o2, t2, "__and__", "__rand__", "&"); } /** - * Implements the Python expression this &= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the iand. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this &= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the iand. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_iand(PyObject o2) { - PyObject x=__iand__(o2); - if (x!=null) { + PyObject x = __iand__(o2); + if (x != null) { return x; } return this._basic_and(o2); @@ -3417,10 +3339,9 @@ final PyObject _basic_iand(PyObject o2) { /** * Equivalent to the standard Python __or__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the or, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the or, or null if this operation is not defined **/ public PyObject __or__(PyObject other) { return null; @@ -3428,10 +3349,9 @@ public PyObject __or__(PyObject other) { /** * Equivalent to the standard Python __ror__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the or, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the or, or null if this operation is not defined. **/ public PyObject __ror__(PyObject other) { return null; @@ -3439,87 +3359,88 @@ public PyObject __ror__(PyObject other) { /** * Equivalent to the standard Python __ior__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the ior, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the ior, or null if this operation is not defined **/ public PyObject __ior__(PyObject other) { return null; } /** - * Implements the Python expression this | o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the or. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this | o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the or. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _or(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_or(o2); } - return _binop_rule(t1,o2,t2,"__or__","__ror__","|"); + return _binop_rule(t1, o2, t2, "__or__", "__ror__", "|"); } /** - * Implements the Python expression this | o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the or. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this | o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the or. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_or(PyObject o2) { - PyObject x=__or__(o2); - if (x!=null) { + PyObject x = __or__(o2); + if (x != null) { return x; } - x=o2.__ror__(this); - if (x!=null) { + x = o2.__ror__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("|",o2)); + throw Py.TypeError(_unsupportedop("|", o2)); } /** - * Implements the Python expression this |= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ior. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this |= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ior. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _ior(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_ior(o2); } - PyObject impl=t1.lookup("__ior__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__ior__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__or__","__ror__","|"); + return _binop_rule(t1, o2, t2, "__or__", "__ror__", "|"); } /** - * Implements the Python expression this |= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ior. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this |= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ior. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_ior(PyObject o2) { - PyObject x=__ior__(o2); - if (x!=null) { + PyObject x = __ior__(o2); + if (x != null) { return x; } return this._basic_or(o2); @@ -3527,10 +3448,9 @@ final PyObject _basic_ior(PyObject o2) { /** * Equivalent to the standard Python __xor__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the xor, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the xor, or null if this operation is not defined **/ public PyObject __xor__(PyObject other) { return null; @@ -3538,10 +3458,9 @@ public PyObject __xor__(PyObject other) { /** * Equivalent to the standard Python __rxor__ method - * @param other the object to perform this binary operation with - * (the left-hand operand). - * @return the result of the xor, or null if this operation - * is not defined. + * + * @param other the object to perform this binary operation with (the left-hand operand). + * @return the result of the xor, or null if this operation is not defined. **/ public PyObject __rxor__(PyObject other) { return null; @@ -3549,87 +3468,88 @@ public PyObject __rxor__(PyObject other) { /** * Equivalent to the standard Python __ixor__ method - * @param other the object to perform this binary operation with - * (the right-hand operand). - * @return the result of the ixor, or null if this operation - * is not defined + * + * @param other the object to perform this binary operation with (the right-hand operand). + * @return the result of the ixor, or null if this operation is not defined **/ public PyObject __ixor__(PyObject other) { return null; } /** - * Implements the Python expression this ^ o2 - * @param o2 the object to perform this binary operation with. - * @return the result of the xor. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this ^ o2} + * + * @param o2 the object to perform this binary operation with. + * @return the result of the xor. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _xor(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_xor(o2); } - return _binop_rule(t1,o2,t2,"__xor__","__rxor__","^"); + return _binop_rule(t1, o2, t2, "__xor__", "__rxor__", "^"); } /** - * Implements the Python expression this ^ o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this binary operation with. - * @return the result of the xor. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this ^ o2} when this and o2 have the same type or are + * builtin types. + * + * @param o2 the object to perform this binary operation with. + * @return the result of the xor. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_xor(PyObject o2) { - PyObject x=__xor__(o2); - if (x!=null) { + PyObject x = __xor__(o2); + if (x != null) { return x; } - x=o2.__rxor__(this); - if (x!=null) { + x = o2.__rxor__(this); + if (x != null) { return x; } - throw Py.TypeError(_unsupportedop("^",o2)); + throw Py.TypeError(_unsupportedop("^", o2)); } /** - * Implements the Python expression this ^= o2 - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ixor. - * @exception Py.TypeError if this operation can't be performed - * with these operands. - **/ + * Implements the Python expression {@code this ^= o2} + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ixor. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. + **/ public final PyObject _ixor(PyObject o2) { - PyType t1=this.getType(); - PyType t2=o2.getType(); - if (t1==t2||t1.builtin&&t2.builtin) { + PyType t1 = this.getType(); + PyType t2 = o2.getType(); + if (t1 == t2 || t1.builtin && t2.builtin) { return this._basic_ixor(o2); } - PyObject impl=t1.lookup("__ixor__"); - if (impl!=null) { - PyObject res=impl.__get__(this,t1).__call__(o2); - if (res!=Py.NotImplemented) { + PyObject impl = t1.lookup("__ixor__"); + if (impl != null) { + PyObject res = impl.__get__(this, t1).__call__(o2); + if (res != Py.NotImplemented) { return res; } } - return _binop_rule(t1,o2,t2,"__xor__","__rxor__","^"); + return _binop_rule(t1, o2, t2, "__xor__", "__rxor__", "^"); } /** - * Implements the Python expression this ^= o2 - * when this and o2 have the same type or are builtin types. - * @param o2 the object to perform this inplace binary - * operation with. - * @return the result of the ixor. - * @exception Py.TypeError if this operation can't be performed - * with these operands. + * Implements the Python expression {@code this ^= o2} when this and o2 have the same type or + * are builtin types. + * + * @param o2 the object to perform this inplace binary operation with. + * @return the result of the ixor. + * @throws PyException {@code TypeError} if this operation can't be performed with these + * operands. **/ final PyObject _basic_ixor(PyObject o2) { - PyObject x=__ixor__(o2); - if (x!=null) { + PyObject x = __ixor__(o2); + if (x != null) { return x; } return this._basic_xor(o2); @@ -3655,8 +3575,7 @@ public PyObject _jcallexc(Object[] args) throws Throwable { Py.maybeSystemExit(e); } if (Options.showPythonProxyExceptions) { - Py.stderr.println( - "Exception in Python proxy returning to Java:"); + Py.stderr.println("Exception in Python proxy returning to Java:"); Py.printException(e); } } @@ -3665,10 +3584,12 @@ public PyObject _jcallexc(Object[] args) throws Throwable { } public void _jthrow(Throwable t) { - if (t instanceof RuntimeException) + if (t instanceof RuntimeException) { throw (RuntimeException) t; - if (t instanceof Error) + } + if (t instanceof Error) { throw (Error) t; + } throw Py.JavaError(t); } @@ -3684,11 +3605,10 @@ public PyObject _jcall(Object[] args) { /* Shortcut methods for calling methods from Java */ /** - * Shortcut for calling a method on a PyObject from Java. - * This form is equivalent to o.__getattr__(name).__call__(args, keywords) + * Shortcut for calling a method on a PyObject from Java. This form is equivalent to + * o.__getattr__(name).__call__(args, keywords) * - * @param name the name of the method to call. This must be an - * interned string! + * @param name the name of the method to call. This must be an interned string! * @param args an array of the arguments to the call. * @param keywords the keywords to use in the call. * @return the result of calling the method name with args and keywords. @@ -3706,8 +3626,7 @@ public PyObject invoke(String name, PyObject[] args) { /** * Shortcut for calling a method on a PyObject with no args. * - * @param name the name of the method to call. This must be an - * interned string! + * @param name the name of the method to call. This must be an interned string! * @return the result of calling the method name with no args **/ public PyObject invoke(String name) { @@ -3718,8 +3637,7 @@ public PyObject invoke(String name) { /** * Shortcut for calling a method on a PyObject with one arg. * - * @param name the name of the method to call. This must be an - * interned string! + * @param name the name of the method to call. This must be an interned string! * @param arg1 the one argument of the method. * @return the result of calling the method name with arg1 **/ @@ -3731,8 +3649,7 @@ public PyObject invoke(String name, PyObject arg1) { /** * Shortcut for calling a method on a PyObject with two args. * - * @param name the name of the method to call. This must be an - * interned string! + * @param name the name of the method to call. This must be an interned string! * @param arg1 the first argument of the method. * @param arg2 the second argument of the method. * @return the result of calling the method name with arg1 and arg2 @@ -3743,16 +3660,13 @@ public PyObject invoke(String name, PyObject arg1, PyObject arg2) { } /** - * Shortcut for calling a method on a PyObject with one extra - * initial argument. + * Shortcut for calling a method on a PyObject with one extra initial argument. * - * @param name the name of the method to call. This must be an - * interned string! + * @param name the name of the method to call. This must be an interned string! * @param arg1 the first argument of the method. * @param args an array of the arguments to the call. * @param keywords the keywords to use in the call. - * @return the result of calling the method name with arg1 args - * and keywords + * @return the result of calling the method name with arg1 args and keywords **/ public PyObject invoke(String name, PyObject arg1, PyObject[] args, String[] keywords) { PyObject f = __getattr__(name); @@ -3761,14 +3675,18 @@ public PyObject invoke(String name, PyObject arg1, PyObject[] args, String[] key /* descriptors and lookup protocols */ - /** xxx implements where meaningful + /** + * xxx implements where meaningful + * * @return internal object per instance dict or null */ public PyObject fastGetDict() { return null; } - /** xxx implements where meaningful + /** + * xxx implements where meaningful + * * @return internal object __dict__ or null */ public PyObject getDict() { @@ -3777,12 +3695,14 @@ public PyObject getDict() { public void setDict(PyObject newDict) { // fallback if setDict not implemented in subclass - throw Py.TypeError("can't set attribute '__dict__' of instance of " + getType().fastGetName()); + throw Py.TypeError( + "can't set attribute '__dict__' of instance of " + getType().fastGetName()); } public void delDict() { // fallback to error - throw Py.TypeError("can't delete attribute '__dict__' of instance of '" + getType().fastGetName()+ "'"); + throw Py.TypeError("can't delete attribute '__dict__' of instance of '" + + getType().fastGetName() + "'"); } public boolean implementsDescrGet() { @@ -3804,14 +3724,11 @@ public boolean isDataDescr() { /** * Get descriptor for this PyObject. * - * @param obj - - * the instance accessing this descriptor. Can be null if this is - * being accessed by a type. - * @param type - - * the type accessing this descriptor. Will be null if obj exists - * as obj is of the type accessing the descriptor. - * @return - the object defined for this descriptor for the given obj and - * type. + * @param obj - the instance accessing this descriptor. Can be null if this is being accessed by + * a type. + * @param type - the type accessing this descriptor. Will be null if obj exists as obj is of the + * type accessing the descriptor. + * @return - the object defined for this descriptor for the given obj and type. */ public PyObject __get__(PyObject obj, PyObject type) { return _doget(obj, type); @@ -3913,7 +3830,7 @@ final void object___delattr__(PyObject name) { public static final String asName(PyObject obj) { try { return obj.asName(0); - } catch(PyObject.ConversionException e) { + } catch (PyObject.ConversionException e) { throw Py.TypeError("attribute name must be a string"); } } @@ -3956,23 +3873,22 @@ final void object___delattr__(String name) { } /** - * Helper to check for object.__setattr__ or __delattr__ applied to a type (The Carlo - * Verre hack). + * Helper to check for object.__setattr__ or __delattr__ applied to a type (The Carlo Verre + * hack). * * @param what String method name to check for */ private void hackCheck(String what) { - if (this instanceof PyType && ((PyType)this).builtin) { - throw Py.TypeError(String.format("can't apply this %s to %s object", what, - objtype.fastGetName())); + if (this instanceof PyType && ((PyType) this).builtin) { + throw Py.TypeError( + String.format("can't apply this %s to %s object", what, objtype.fastGetName())); } } /** - * A common helper method, use to prevent infinite recursion - * when a Python object implements __reduce__ and sometimes calls - * object.__reduce__. Trying to do it all in __reduce__ex__ caused - # this problem. See http://bugs.jython.org/issue2323. + * A common helper method, use to prevent infinite recursion when a Python object implements + * __reduce__ and sometimes calls object.__reduce__. Trying to do it all in __reduce__ex__ + * caused # this problem. See http://bugs.jython.org/issue2323. */ private PyObject commonReduce(int proto) { PyObject res; @@ -3988,7 +3904,7 @@ private PyObject commonReduce(int proto) { } /** - * Used for pickling. Default implementation calls object___reduce__. + * Used for pickling. Default implementation calls object___reduce__. * * @return a tuple of (class, tuple) */ @@ -4001,17 +3917,18 @@ final PyObject object___reduce__() { return commonReduce(0); } - /** Used for pickling. If the subclass specifies __reduce__, it will - * override __reduce_ex__ in the base-class, even if __reduce_ex__ was - * called with an argument. + /** + * Used for pickling. If the subclass specifies __reduce__, it will override __reduce_ex__ in + * the base-class, even if __reduce_ex__ was called with an argument. * - * @param arg PyInteger specifying reduce algorithm (method without this - * argument defaults to 0). + * @param arg PyInteger specifying reduce algorithm (method without this argument defaults to + * 0). * @return a tuple of (class, tuple) */ public PyObject __reduce_ex__(int arg) { return object___reduce_ex__(arg); } + public PyObject __reduce_ex__() { return object___reduce_ex__(0); } @@ -4052,7 +3969,7 @@ private static PyObject slotnames(PyObject cls) { private PyObject reduce_2() { PyObject args, state; PyObject res = null; - int n,i; + int n, i; PyObject cls = this.__findattr__("__class__"); @@ -4090,8 +4007,8 @@ private PyObject reduce_2() { PyObject slots = new PyDictionary(); n = 0; - for (i = 0; i < ((PyList)names).size(); i++) { - PyObject name = ((PyList)names).pyget(i); + for (i = 0; i < ((PyList) names).size(); i++) { + PyObject name = ((PyList) names).pyget(i); PyObject value = this.__findattr__(name.toString()); if (null == value) { // do nothing @@ -4110,7 +4027,7 @@ private PyObject reduce_2() { if (!(this instanceof PyList)) { listitems = Py.None; } else { - listitems = ((PyList)this).__iter__(); + listitems = ((PyList) this).__iter__(); } if (!(this instanceof PyDictionary)) { dictitems = Py.None; @@ -4121,11 +4038,11 @@ private PyObject reduce_2() { PyObject copyreg = __builtin__.__import__("copy_reg", null, null, Py.EmptyTuple); PyObject newobj = copyreg.__findattr__("__newobj__"); - n = ((PyTuple)args).size(); - PyObject args2[] = new PyObject[n+1]; + n = ((PyTuple) args).size(); + PyObject args2[] = new PyObject[n + 1]; args2[0] = cls; - for(i = 0; i < n; i++) { - args2[i+1] = ((PyTuple)args).pyget(i); + for (i = 0; i < n; i++) { + args2[i + 1] = ((PyTuple) args).pyget(i); } return new PyTuple(newobj, new PyTuple(args2), state, listitems, dictitems); @@ -4157,15 +4074,15 @@ public String asString(int index) throws ConversionException { throw new ConversionException(index); } - public String asString(){ + public String asString() { throw Py.TypeError("expected a str"); } public String asStringOrNull(int index) throws ConversionException { - return asString(index); + return asString(index); } - public String asStringOrNull(){ + public String asStringOrNull() { return asString(); } @@ -4268,12 +4185,11 @@ public int asIndex(PyObject err) { } } -/* - * A very specialized tuple-like class used when detecting cycles during - * object comparisons. This classes is different from an normal tuple - * by hashing and comparing its elements by identity. - */ +/** + * A very specialized tuple-like class used when detecting cycles during object comparisons. This + * classes is different from an normal tuple by hashing and comparing its elements by identity. + */ class PyIdentityTuple extends PyObject implements Traverseproc { PyObject[] list; @@ -4298,25 +4214,27 @@ public int hashCode() { @Override public boolean equals(Object o) { - if (!(o instanceof PyIdentityTuple)) + if (!(o instanceof PyIdentityTuple)) { return false; + } PyIdentityTuple that = (PyIdentityTuple) o; - if (list.length != that.list.length) + if (list.length != that.list.length) { return false; + } for (int i = 0; i < list.length; i++) { - if (list[i] != that.list[i]) + if (list[i] != that.list[i]) { return false; + } } return true; } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { if (list != null) { int retVal; - for (PyObject ob: list) { + for (PyObject ob : list) { if (ob != null) { retVal = visit.visit(ob, arg); if (retVal != 0) { @@ -4333,7 +4251,7 @@ public boolean refersDirectlyTo(PyObject ob) { if (ob == null || list == null) { return false; } - for (PyObject obj: list) { + for (PyObject obj : list) { if (ob == obj) { return true; } diff --git a/src/org/python/core/PyObjectDerived.java b/src/org/python/core/PyObjectDerived.java index b0676d235..79c4e95f9 100644 --- a/src/org/python/core/PyObjectDerived.java +++ b/src/org/python/core/PyObjectDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyPropertyDerived.java b/src/org/python/core/PyPropertyDerived.java index 22f94a15d..157564909 100644 --- a/src/org/python/core/PyPropertyDerived.java +++ b/src/org/python/core/PyPropertyDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyReflectedConstructor.java b/src/org/python/core/PyReflectedConstructor.java index c9a680bde..0dcdcebf5 100644 --- a/src/org/python/core/PyReflectedConstructor.java +++ b/src/org/python/core/PyReflectedConstructor.java @@ -1,4 +1,6 @@ // Copyright (c) Corporation for National Research Initiatives +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; import java.lang.reflect.Constructor; @@ -40,7 +42,7 @@ PyObject make(PyObject[] args, String[] keywords) { // Check for a matching constructor to call if (nargs > 0) { // PyArgsKeywordsCall signature, if present, is the first if (argslist[0].matches(null, args, keywords, callData)) { - method = argslist[0].data; + method = argslist[0].method; consumes_keywords = argslist[0].flags == ReflectedArgs.PyArgsKeywordsCall; } else { allArgs = args; @@ -52,7 +54,7 @@ PyObject make(PyObject[] args, String[] keywords) { } for (; i < nargs; i++) { if (argslist[i].matches(null, args, Py.NoKeywords, callData)) { - method = argslist[i].data; + method = argslist[i].method; break; } } @@ -116,7 +118,7 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { } ReflectedCallData callData = new ReflectedCallData(); Object method = null; - + // If we have keyword args, there are two ways this can be handled; // a) we find a constructor that takes keyword args, and use it. // b) we don't, in which case we strip the keyword args, and pass the @@ -129,25 +131,25 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { boolean usingKeywordArgsCtor = false; if (nkeywords > 0) { // We have keyword args. - + // Look for a constructor; the ReflectedArgs#matches() method exits early in the case // where keyword args are used int n = nargs; for (int i = 0; i < n; i++) { rargs = argslist[i]; if (rargs.matches(null, args, keywords, callData)) { - method = rargs.data; + method = rargs.method; break; } } - + if (method != null) { // Constructor found that will accept the keyword args usingKeywordArgsCtor = true; } else { // No constructor found that will take keyword args - - // Remove the keyword args + + // Remove the keyword args args = new PyObject[allArgs.length - nkeywords]; System.arraycopy(allArgs, 0, args, 0, args.length); @@ -155,7 +157,7 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { for (int i = 0; i < n; i++) { rargs = argslist[i]; if (rargs.matches(null, args, Py.NoKeywords, callData)) { - method = rargs.data; + method = rargs.method; break; } } @@ -166,12 +168,12 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { for (int i = 0; i < n; i++) { rargs = argslist[i]; if (rargs.matches(null, args, Py.NoKeywords, callData)) { - method = rargs.data; + method = rargs.method; break; } } } - + // Throw an error if no valid set of arguments if (method == null) { throwError(callData.errArg, args.length, false, false); @@ -217,8 +219,9 @@ protected void constructProxy(PyObject obj, Constructor ctor, Object[] args, msg += " " + sup.getName(); } throw Py.TypeError(msg); - } else + } else { throw Py.JavaError(e); + } } catch (Throwable t) { throw Py.JavaError(t); } diff --git a/src/org/python/core/PyReflectedFunction.java b/src/org/python/core/PyReflectedFunction.java index efa026437..53d2b8dbc 100644 --- a/src/org/python/core/PyReflectedFunction.java +++ b/src/org/python/core/PyReflectedFunction.java @@ -1,4 +1,6 @@ // Copyright (c) Corporation for National Research Initiatives +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; import java.lang.reflect.Method; @@ -13,6 +15,8 @@ public class PyReflectedFunction extends PyObject implements Traverseproc { public PyObject __doc__ = Py.None; + public PyObject __module__ = Py.None; + public ReflectedArgs[] argslist = new ReflectedArgs[1]; public int nargs; @@ -64,6 +68,7 @@ private ReflectedArgs makeArgs(Method m) { public PyReflectedFunction copy() { PyReflectedFunction func = new PyReflectedFunction(__name__); func.__doc__ = __doc__; + func.__module__ = __module__; func.nargs = nargs; func.argslist = new ReflectedArgs[nargs]; System.arraycopy(argslist, 0, func.argslist, 0, nargs); @@ -158,7 +163,6 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { ReflectedCallData callData = new ReflectedCallData(); ReflectedArgs match = null; for (int i = 0; i < nargs && match == null; i++) { - // System.err.println(rargs.toString()); if (argslist[i].matches(self, args, keywords, callData)) { match = argslist[i]; } @@ -167,7 +171,7 @@ public PyObject __call__(PyObject self, PyObject[] args, String[] keywords) { throwError(callData.errArg, args.length, self != null, keywords.length != 0); } Object cself = callData.self; - Method m = (Method)match.data; + Method m = (Method)match.method; // If this is a direct call to a Java class instance method with a PyProxy instance as the // arg, use the super__ version to actually route this through the method on the class. @@ -340,11 +344,17 @@ public String toString() { /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { + if (__module__ != null) { + int res = visit.visit(__module__, arg); + if (res != 0) { + return res; + } + } return __doc__ != null ? visit.visit(__doc__, arg) : 0; } @Override public boolean refersDirectlyTo(PyObject ob) { - return ob != null && ob == __doc__; + return ob != null && (ob == __doc__ || ob == __module__); } } diff --git a/src/org/python/core/PyRunnable.java b/src/org/python/core/PyRunnable.java index a7207be9f..fb2952bed 100644 --- a/src/org/python/core/PyRunnable.java +++ b/src/org/python/core/PyRunnable.java @@ -5,10 +5,7 @@ * Interface implemented by compiled modules which allow access to * to the module code object. */ - public interface PyRunnable { - /** - * Return the modules code object. - */ + /** Return the module's code object. */ abstract public PyCode getMain(); } diff --git a/src/org/python/core/PyRunnableBootstrap.java b/src/org/python/core/PyRunnableBootstrap.java index cf33f61de..c8e5b341b 100644 --- a/src/org/python/core/PyRunnableBootstrap.java +++ b/src/org/python/core/PyRunnableBootstrap.java @@ -12,6 +12,19 @@ public class PyRunnableBootstrap implements CodeBootstrap { } public PyCode loadCode(CodeLoader loader) { + if (runnable instanceof ContainsPyBytecode) { + try { + BytecodeLoader.fixPyBytecode(((ContainsPyBytecode) runnable).getClass()); + } catch (NoSuchFieldException e) { + throw Py.JavaError(e); + } catch (java.io.IOException e) { + throw Py.JavaError(e); + } catch (ClassNotFoundException e) { + throw Py.JavaError(e); + } catch (IllegalAccessException e) { + throw Py.JavaError(e); + } + } return runnable.getMain(); } @@ -29,15 +42,27 @@ public static CodeBootstrap getFilenameConstructorReflectionBootstrap( public PyCode loadCode(CodeLoader loader) { try { - return constructor.newInstance(loader.filename).getMain(); + PyRunnable result = constructor.newInstance(loader.filename); + if (result instanceof ContainsPyBytecode) { + try { + BytecodeLoader.fixPyBytecode(((ContainsPyBytecode) result).getClass()); + } catch (NoSuchFieldException e) { + throw Py.JavaError(e); + } catch (java.io.IOException e) { + throw Py.JavaError(e); + } catch (ClassNotFoundException e) { + throw Py.JavaError(e); + } catch (IllegalAccessException e) { + throw Py.JavaError(e); + } + } + return result.getMain(); } catch (Exception e) { throw new IllegalArgumentException( "PyRunnable class constructor does not support instantiation protocol.", e); } } - }; } - } diff --git a/src/org/python/core/PySequence.java b/src/org/python/core/PySequence.java index 6c2da1656..b829d7165 100644 --- a/src/org/python/core/PySequence.java +++ b/src/org/python/core/PySequence.java @@ -280,8 +280,8 @@ protected boolean isSubType(PyObject other) { /** * Compare the specified object/length pairs. * - * @return value >= 0 is the index where the sequences differs. -1: reached the end of o1 - * without a difference -2: reached the end of both seqeunces without a difference -3: + * @return value ≥ 0 is the index where the sequences differs. -1: reached the end of o1 + * without a difference -2: reached the end of both sequences without a difference -3: * reached the end of o2 without a difference */ protected static int cmp(PyObject o1, int ol1, PyObject o2, int ol2) { @@ -334,8 +334,9 @@ protected static final int sliceLength(int start, int stop, long step) { } /** - * Adjusts index such that it's >= 0 and <= __len__. If index starts - * off negative, it's treated as an index from the end of the sequence going back to the start. + * Adjusts index such that it's ≥0 and ≤ __len__. If index + * starts off negative, it's treated as an index from the end of the sequence going back to the + * start. */ protected int boundToSequence(int index) { int length = __len__(); diff --git a/src/org/python/core/PySetDerived.java b/src/org/python/core/PySetDerived.java index 7f1459959..6fdcf9e49 100644 --- a/src/org/python/core/PySetDerived.java +++ b/src/org/python/core/PySetDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyShadowString.java b/src/org/python/core/PyShadowString.java new file mode 100644 index 000000000..f63e40820 --- /dev/null +++ b/src/org/python/core/PyShadowString.java @@ -0,0 +1,302 @@ +package org.python.core; + +import java.util.regex.Pattern; + +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedNew; +import org.python.expose.ExposedType; +import org.python.expose.MethodType; + +/** + * This class provides a string that sometimes seems to change value, as far as equality tests and + * startswith are concerned. This solves a problem that Jython users sometimes + * experience with libraries that are sensitive to platform. + *

    + * A library may test for a particular platform in order to adjust to local file name conventions or + * to decide which operating system commands are available. In Jython, os.name and + * sys.platform indicate that Java is the platform, which is necessary information in + * some parts of the standard library, but other libraries assuming CPython then draw incorrect + * conclusions. + *

    + * With hindsight, a better choice could be made, where sys.platform etc. indicated + * Windows or Posix, and something else indicates the implementation. A change in Jython 2 would + * cause more problems than it solved, but we expect Jython 3 to work that way. In the Python + * Standard Library, the Jython project can make all necessary changes. It can't do anything about + * third-party libraries. But it would be a big help if users could cause sys.platform + * or os.name to appear to have the OS-dependent value as far as those troublesome + * libraries were concerned. + *

    + * This is what this class achieves. os.name and sys.platform regular + * strings for most purposes, but each has a "shadow" value that is used in contexts the user may + * specify. + */ +@Untraversable +@ExposedType(name = "shadowstr", base = PyString.class, isBaseType = true) +public class PyShadowString extends PyString { + + public static final PyType TYPE = PyType.fromClass(PyShadowString.class); + + /** + * Contexts (expressed as a {@link PyTuple} of class name and method name) where {@link #shadow} + * is allowed to match as well as the primary value. + */ + protected PyList targets; + + /** + * The shadow string is additionally used for some comparisons, especially for __eq__. __eq__ + * will evaluate positive if the other string equals the primary value *or* the shadow. The + * shadow persists slicing (is sliced accordingly) and is taken into account by startswith. + */ + protected PyString shadow; + + /** Empty string (not very useful but needed for technical reasons). */ + public PyShadowString() { + this(Py.EmptyString, Py.EmptyString); + } + + /** Construct an instance specifying primary and shadow values. */ + public PyShadowString(String primary, String shadow) { + this(TYPE, Py.newString(primary), Py.newString(shadow), new PyList()); + } + + /** + * Construct an instance specifying primary and shadow values + * (bytes object expected for primary). + * This somewhat uncanonical constructor was removed in Jython 2.7.2. + * The deprecated version is kept for compatibility with JyNI 2.7-alpha5. + * + * @deprecated use the constructor with strings instead. + */ + @Deprecated + public PyShadowString(PyObject primary, String shadow) { + this(TYPE, primary, Py.newString(shadow), new PyList()); + } + + /** Construct an instance specifying primary and shadow values (bytes objects expected). */ + private PyShadowString(PyObject primary, PyObject shadow) { + this(TYPE, primary, shadow, new PyList()); + } + + private PyShadowString(PyObject primary, PyObject shadow, PyList targets) { + this(TYPE, primary, shadow, targets); + } + + public PyShadowString(PyType subtype, PyObject primary, PyObject shadow) { + this(subtype, primary, shadow, new PyList()); + } + + private PyShadowString(PyType subtype, PyObject primary, PyObject shadow, PyList targets) { + super(subtype, primary.__str__().getString()); + this.shadow = shadow.__str__(); + this.targets = targets; + } + + @ExposedNew + static PyObject shadowstr_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, + String[] keywords) { + ArgParser ap = + new ArgParser("shadowstr", args, keywords, new String[] {"primary", "shadow"}, 0); + + PyObject valueObj = ap.getPyObject(0, Py.EmptyString); + PyObject shadowObj = ap.getPyObject(1, Py.EmptyString); + + if (valueObj instanceof PyString && shadowObj instanceof PyString) { + return new PyShadowString(valueObj, shadowObj); + } else { + String message = String.format("arguments must be strings not (%.200s, %.200s)", + valueObj.getType(), shadowObj.getType()); + throw Py.TypeError(message); + } + } + + /** Convert a PyObject (specifying a regex) to a compiled pattern or null. */ + private static Pattern getPattern(PyObject o) { + if (o instanceof PyString) { + return Pattern.compile(o.toString()); + } else { + return null; + } + } + + /** + * Test whether the current code is executing in of one of the target contexts, by searching up + * the stack for a class and method pait that match. + * + * @return true iff in one of the named contexts + */ + private boolean isTarget() { + // Get a stack trace by constructing an exception here + Exception exc = new Exception(); + + for (PyObject obj : targets.getList()) { + // Only process proper tuple entries + if (obj instanceof PyTuple && ((PyTuple) obj).__len__() >= 2) { + + // Compile the target specification + PyTuple target = (PyTuple) obj; + Pattern clazz = getPattern(target.__finditem__(0)); + Pattern method = getPattern(target.__finditem__(1)); + + // Now scan the stack using this pair of patterns + for (StackTraceElement ste : exc.getStackTrace()) { + if (clazz == null || clazz.matcher(ste.getClassName()).matches()) { + // Either we don't care about the class it matches, and ... + if ((method == null || method.matcher(ste.getMethodName()).matches())) { + // Either we don't care about the method name or it matches + return true; + } + } + } + } + } + + // Nothing matched + return false; + } + + /** Get the shadow value. */ + public PyString getshadow() { + return shadowstr_getshadow(); + } + + @ExposedMethod + public final PyString shadowstr_getshadow() { + return shadow; + } + + /** + * Specify a context (class, method) in which the shadow string is allowed to match. + * + * @param className class name to match or null to match anything. + * @param methodName method name to match or null to match anything. + */ + public void addTarget(String className, String methodName) { + shadowstr_addtarget( // + className == null ? Py.None : Py.newUnicode(className), + methodName == null ? Py.None : Py.newUnicode(methodName)); + } + + @ExposedMethod(defaults = {"null"}) + public final void shadowstr_addtarget(PyObject classname, PyObject methodname) { + // In principle these could be unicode strings + PyTuple entry = new PyTuple(asUnicode(classname), asUnicode(methodname)); + targets.add(entry); + } + + /** Prepare argument for addtarget, allowing string-like values or None. */ + private static PyObject asUnicode(PyObject o) { + if (o == null || o == Py.None) { + return Py.None; + } else if (o instanceof PyString) { + return o.__unicode__(); + } + throw Py.TypeError(String.format("string or None required, not %.200s", o.getType())); + } + + /** + * Return a list of the tuples specifying the contexts in which the shadow value will be + * consulted during matching. + */ + public PyList getTargets() { + return (PyList) shadowstr_gettargets(); + } + + @ExposedMethod + public final PyObject shadowstr_gettargets() { + return targets; + } + + /** + * Compare this PyShadowString with another PyObject for equality. A + * PyShadowString is equal to the other object if its primary value is equal to it, + * or if its shadow value is equal to the other object and the test is made in one of its target + * contexts. (Two PyShadowString are equal if the primary values are equal, the + * primary of one matches the shadow of the other in the shadow's context, or their shadows + * match and both are in context. + * + * @param other to compare + * @return PyBoolean result (or null if not implemented) + */ + @Override + public PyObject __eq__(PyObject other) { + return shadowstr___eq__(other); + } + + @ExposedMethod(type = MethodType.BINARY) + final PyObject shadowstr___eq__(PyObject other) { + // Re-wrap the primary value as a PyString to invoke the right kind of equality test. + PyObject result = testEqual(new PyString(getString()), other); + if (result != Py.False) { + // True, or null if str does not know how to compare with other (so we don't either). + return result; + + } else if (targets.isEmpty()) { + // We aren't going to be using our shadow string + return Py.False; + + } else { + // Since we have targets, compare the shadow string with the other object. + result = testEqual(shadow, other); + if (result == Py.True) { + // It matches, so the result is true iff we are in a target context + return Py.newBoolean(isTarget()); + } else { + return result; + } + } + } + + /** + * Test for equality, used as a helper to shadowstr___eq__, dealing with the + * possibility that other is another PyShadowString. + */ + private static final PyObject testEqual(PyString string, PyObject other) { + if (other instanceof PyShadowString) { + return ((PyShadowString) other).shadowstr___eq__(string); + } else { + return string.__eq__(other); + } + } + + @Override + public PyObject __getslice__(PyObject start, PyObject stop, PyObject step) { + PyObject primary = super.__getslice__(start, stop, step); + PyObject shadow = this.shadow.__getslice__(start, stop, step); + + return new PyShadowString(primary, shadow, targets); + } + + @Override + public boolean startswith(PyObject prefix) { + return shadowstr_startswith(prefix, null, null); + } + + @Override + public boolean startswith(PyObject prefix, PyObject start) { + return shadowstr_startswith(prefix, start, null); + } + + @Override + public boolean startswith(PyObject prefix, PyObject start, PyObject end) { + return shadowstr_startswith(prefix, start, end); + } + + @ExposedMethod(defaults = {"null", "null"}) + final boolean shadowstr_startswith(PyObject prefix, PyObject startObj, PyObject endObj) { + return super.startswith(prefix, startObj, endObj) // + || (!targets.isEmpty() && shadow.startswith(prefix, startObj, endObj) + && isTarget()); + } + + @Override + public PyString __repr__() { + return shadowstr___repr__(); + } + + @ExposedMethod + final PyString shadowstr___repr__() { + // What you'd type to get this instance (without targets). + String fmt = "PyShadowString(%.200s, %.200s)"; + return Py.newString(String.format(fmt, super.__repr__(), shadow.__repr__())); + } +} diff --git a/src/org/python/core/PyShadowStringDerived.java b/src/org/python/core/PyShadowStringDerived.java new file mode 100644 index 000000000..a5e5048d5 --- /dev/null +++ b/src/org/python/core/PyShadowStringDerived.java @@ -0,0 +1,1162 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.core; + +import java.io.Serializable; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class PyShadowStringDerived extends PyShadowString implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + +} diff --git a/src/org/python/core/PyString.java b/src/org/python/core/PyString.java index 98a0994d0..193d03932 100644 --- a/src/org/python/core/PyString.java +++ b/src/org/python/core/PyString.java @@ -5,9 +5,9 @@ import java.lang.ref.SoftReference; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,6 +49,16 @@ public PyString() { this("", true); } + protected PyString(PyType subType, String string, boolean isBytes) { + super(subType); + if (string == null) { + throw new IllegalArgumentException("Cannot create PyString from null"); + } else if (!isBytes && !isBytes(string)) { + throw new IllegalArgumentException("Cannot create PyString with non-byte value"); + } + this.string = string; + } + /** * Fundamental constructor for PyString objects when the client provides a Java * String, necessitating that we range check the characters. @@ -57,13 +67,7 @@ public PyString() { * @param string a Java String to be wrapped */ public PyString(PyType subType, String string) { - super(subType); - if (string == null) { - throw new IllegalArgumentException("Cannot create PyString from null"); - } else if (!isBytes(string)) { - throw new IllegalArgumentException("Cannot create PyString with non-byte value"); - } - this.string = string; + this(subType, string, false); } public PyString(String string) { @@ -75,7 +79,11 @@ public PyString(char c) { } PyString(StringBuilder buffer) { - this(TYPE, new String(buffer)); + this(TYPE, buffer.toString()); + } + + PyString(PyBuffer buffer) { + this(TYPE, buffer.toString()); } /** @@ -164,7 +172,7 @@ static PyObject str_new(PyNewWrapper new_, boolean init, PyType subtype, PyObjec S = S.__str__(); if (S instanceof PyUnicode) { // Encoding will raise UnicodeEncodeError if not 7-bit clean. - str = codecs.encode((PyUnicode)S, null, null); + str = codecs.encode((PyUnicode) S, null, null); } else { // Must be str/bytes, and should be 8-bit clean already. str = S.toString(); @@ -257,7 +265,7 @@ final PyString str___str__() { @Override public PyUnicode __unicode__() { - return new PyUnicode(this); + return new PyUnicode(this); // Decodes with default codec. } @Override @@ -298,22 +306,54 @@ final PyString str___repr__() { private static char[] hexdigit = "0123456789abcdef".toCharArray(); public static String encode_UnicodeEscape(String str, boolean use_quotes) { - int size = str.length(); - StringBuilder v = new StringBuilder(str.length()); + char quote = use_quotes ? '?' : 0; + return encode_UnicodeEscape(str, quote); + } + + /** + * The inner logic of the string __repr__ producing an ASCII representation of the target + * string, optionally in quotations. The caller can determine whether the returned string will + * be wrapped in quotation marks, and whether Python rules are used to choose them through + * quote. + * + * @param str + * @param quoteChar '"' or '\'' use that, '?' = let Python choose, 0 or anything = no quotes + * @return encoded string (possibly the same string if unchanged) + */ + static String encode_UnicodeEscape(String str, char quote) { + + // Choose whether to quote and the actual quote character + boolean use_quotes; + switch (quote) { + case '?': + use_quotes = true; + // Python rules + quote = str.indexOf('\'') >= 0 && str.indexOf('"') == -1 ? '"' : '\''; + break; + case '"': + case '\'': + use_quotes = true; + break; + default: + use_quotes = false; + break; + } - char quote = 0; + // Allocate a buffer for the result (25% bigger and room for quotes) + int size = str.length(); + StringBuilder v = new StringBuilder(size + (size >> 2) + 2); if (use_quotes) { - quote = str.indexOf('\'') >= 0 && str.indexOf('"') == -1 ? '"' : '\''; v.append(quote); } + // Now chunter through the original string a character at a time for (int i = 0; size-- > 0;) { int ch = str.charAt(i++); - /* Escape quotes */ + // Escape quotes and backslash if ((use_quotes && ch == quote) || ch == '\\') { v.append('\\'); - v.append((char)ch); + v.append((char) ch); continue; } /* Map UTF-16 surrogate pairs to Unicode \UXXXXXXXX escapes */ @@ -361,13 +401,16 @@ else if (ch == '\t') { v.append(hexdigit[(ch >> 4) & 0xf]); v.append(hexdigit[ch & 0xf]); } else {/* Copy everything else as-is */ - v.append((char)ch); + v.append((char) ch); } } + if (use_quotes) { v.append(quote); } - return v.toString(); + + // Return the original string if we didn't quote or escape anything + return v.length() > size ? v.toString() : str; } private static ucnhashAPI pucnHash = null; @@ -393,7 +436,7 @@ public static String decode_UnicodeEscape(String str, int start, int end, String } ch = str.charAt(s++); switch (ch) { - /* \x escapes */ + /* \x escapes */ case '\n': break; case '\\': @@ -443,7 +486,7 @@ public static String decode_UnicodeEscape(String str, int start, int end, String } x = (x << 3) + Character.digit(ch, 8); } - v.append((char)x); + v.append((char) x); break; case 'x': s = hexescape(v, errors, 2, s, str, end, "truncated \\xXX"); @@ -477,7 +520,7 @@ public static String decode_UnicodeEscape(String str, int start, int end, String if (pucnHash == null) { PyObject mod = imp.importName("ucnhash", true); mod = mod.__call__(); - pucnHash = (ucnhashAPI)mod.__tojava__(Object.class); + pucnHash = (ucnhashAPI) mod.__tojava__(Object.class); if (pucnHash.getCchMax() < 0) { throw Py.UnicodeError("Unicode names not loaded"); } @@ -525,8 +568,8 @@ public static String decode_UnicodeEscape(String str, int start, int end, String private static int hexescape(StringBuilder partialDecode, String errors, int digits, int hexDigitStart, String str, int size, String errorMessage) { if (hexDigitStart + digits > size) { - return codecs.insertReplacementAndGetResume(partialDecode, errors, "unicodeescape", - str, hexDigitStart - 2, size, errorMessage); + return codecs.insertReplacementAndGetResume(partialDecode, errors, "unicodeescape", str, + hexDigitStart - 2, size, errorMessage); } int i = 0; int x = 0; @@ -549,8 +592,8 @@ private static int hexescape(StringBuilder partialDecode, String errors, int dig if (storeUnicodeCharacter(x, partialDecode)) { return hexDigitStart + i; } else { - return codecs.insertReplacementAndGetResume(partialDecode, errors, "unicodeescape", - str, hexDigitStart - 2, hexDigitStart + i + 1, "illegal Unicode character"); + return codecs.insertReplacementAndGetResume(partialDecode, errors, "unicodeescape", str, + hexDigitStart - 2, hexDigitStart + i + 1, "illegal Unicode character"); } } @@ -591,7 +634,7 @@ final int str___cmp__(PyObject other) { return -2; } - int c = getString().compareTo(((PyString)other).getString()); + int c = getString().compareTo(((PyString) other).getString()); return c < 0 ? -1 : c > 0 ? 1 : 0; } @@ -679,8 +722,9 @@ final PyObject str___ge__(PyObject other) { return getString().compareTo(s) >= 0 ? Py.True : Py.False; } + /** Interpret the object as a Java String representing bytes or return null. */ private static String coerce(PyObject o) { - if (o instanceof PyString) { + if (o instanceof PyString && !(o instanceof PyUnicode)) { return o.toString(); } return null; @@ -707,12 +751,18 @@ public byte[] toBytes() { @Override public Object __tojava__(Class c) { if (c.isAssignableFrom(String.class)) { - return getString(); + /* + * If c is a CharSequence we assume the caller is prepared to get maybe not an actual + * String. In that case we avoid conversion so the caller can do special stuff with the + * returned PyString or PyUnicode or whatever. (If c is Object.class, the caller usually + * expects to get actually a String) + */ + return c == CharSequence.class ? this : getString(); } if (c == Character.TYPE || c == Character.class) { if (getString().length() == 1) { - return new Character(getString().charAt(0)); + return getString().charAt(0); } } @@ -774,7 +824,7 @@ protected PyObject getslice(int start, int stop, int step) { * This is to be overridden in a subclass to return its own type. * * @param str to wrap - * @return + * @return instance wrapping {@code str} */ public PyString createInstance(String str) { return new PyString(str); @@ -784,9 +834,9 @@ public PyString createInstance(String str) { * Create an instance of the same type as this object, from the Java String given as argument. * This is to be overridden in a subclass to return its own type. * - * @param string UTF-16 string encoding the characters (as Java). + * @param str Java string representing the characters (as Java UTF-16). * @param isBasic is ignored in PyString (effectively true). - * @return + * @return instance wrapping {@code str} */ protected PyString createInstance(String str, boolean isBasic) { // ignore isBasic, doesn't apply to PyString, just PyUnicode @@ -794,21 +844,23 @@ protected PyString createInstance(String str, boolean isBasic) { } /** - * Return a String equivalent to the argument. This is a helper function to those methods that - * accept any byte array type (any object that supports a one-dimensional byte buffer), or - * accept a unicode argument which they interpret from its UTF-16 encoded form (the - * internal representation returned by {@link PyUnicode#getString()}). + * Return a Java String that is the Jython-internal equivalent of the byte-like + * argument (a str or any object that supports a one-dimensional byte buffer). If + * the argument is not acceptable (this includes a unicode argument) return null. * * @param obj to coerce to a String * @return coerced value or null if it can't be */ - private static String asUTF16StringOrNull(PyObject obj) { + private static String asU16BytesOrNull(PyObject obj) { if (obj instanceof PyString) { - // str or unicode object: go directly to the String - return ((PyString)obj).getString(); + if (obj instanceof PyUnicode) { + return null; + } + // str but not unicode object: go directly to the String + return ((PyString) obj).getString(); } else if (obj instanceof BufferProtocol) { // Other object with buffer API: briefly access the buffer - try (PyBuffer buf = ((BufferProtocol)obj).getBuffer(PyBUF.FULL_RO)) { + try (PyBuffer buf = ((BufferProtocol) obj).getBuffer(PyBUF.FULL_RO)) { return buf.toString(); } } else { @@ -816,18 +868,6 @@ private static String asUTF16StringOrNull(PyObject obj) { } } - /** - * Return a String equivalent to the argument. This is a helper function to those methods that - * accept any byte array type (any object that supports a one-dimensional byte buffer), but - * not a unicode. - * - * @param obj to coerce to a String - * @return coerced value or null if it can't be (including unicode) - */ - private static String asStringOrNull(PyObject obj) { - return (obj instanceof PyUnicode) ? null : asUTF16StringOrNull(obj); - } - /** * Return a String equivalent to the argument. This is a helper function to those methods that * accept any byte array type (any object that supports a one-dimensional byte buffer), but @@ -835,10 +875,10 @@ private static String asStringOrNull(PyObject obj) { * * @param obj to coerce to a String * @return coerced value - * @throws PyException if the coercion fails (including unicode) + * @throws PyException {@code TypeError} if the coercion fails (including unicode) */ - private static String asStringOrError(PyObject obj) throws PyException { - String ret = (obj instanceof PyUnicode) ? null : asUTF16StringOrNull(obj); + protected static String asU16BytesOrError(PyObject obj) throws PyException { + String ret = asU16BytesOrNull(obj); if (ret != null) { return ret; } else { @@ -859,12 +899,11 @@ private static String asStringOrError(PyObject obj) throws PyException { * @return coerced value or null * @throws PyException if the coercion fails (including unicode) */ - private static String asStringNullOrError(PyObject obj, String name) throws PyException { - + private static String asU16BytesNullOrError(PyObject obj, String name) throws PyException { if (obj == null || obj == Py.None) { return null; } else { - String ret = (obj instanceof PyUnicode) ? null : asUTF16StringOrNull(obj); + String ret = asU16BytesOrNull(obj); if (ret != null) { return ret; } else if (name == null) { @@ -877,26 +916,6 @@ private static String asStringNullOrError(PyObject obj, String name) throws PyEx } } - /** - * Return a String equivalent to the argument according to the calling conventions of the - * certain methods of str. Those methods accept as a byte string anything bearing - * the buffer interface, or accept a unicode argument which they interpret from its - * UTF-16 encoded form (the internal representation returned by {@link PyUnicode#getString()}). - * - * @param obj to coerce to a String - * @return coerced value - * @throws PyException if the coercion fails - */ - private static String asUTF16StringOrError(PyObject obj) { - // PyUnicode accepted here. Care required in the client if obj is not basic plane. - String ret = asUTF16StringOrNull(obj); - if (ret != null) { - return ret; - } else { - throw Py.TypeError("expected str, bytearray, unicode or buffer compatible object"); - } - } - @Override public boolean __contains__(PyObject o) { return str___contains__(o); @@ -904,8 +923,15 @@ public boolean __contains__(PyObject o) { @ExposedMethod(doc = BuiltinDocs.str___contains___doc) final boolean str___contains__(PyObject o) { - String other = asUTF16StringOrError(o); - return getString().indexOf(other) >= 0; + String other = asU16BytesOrNull(o); + if (other != null) { + return getString().indexOf(other) >= 0; + } else if (o instanceof PyUnicode) { + return decode().__contains__(o); + } else { + throw Py.TypeError("'in ' requires string as left operand, not " + + (o == null ? Py.None : o).getType().fastGetName()); + } } @Override @@ -914,7 +940,7 @@ protected PyObject repeat(int count) { count = 0; } int s = getString().length(); - if ((long)s * count > Integer.MAX_VALUE) { + if ((long) s * count > Integer.MAX_VALUE) { // Since Strings store their data in an array, we can't make one // longer than Integer.MAX_VALUE. Without this check we get // NegativeArraySize exceptions when we create the array on the @@ -967,12 +993,12 @@ public PyObject __add__(PyObject other) { @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.str___add___doc) final PyObject str___add__(PyObject other) { // Expect other to be some kind of byte-like object. - String otherStr = asStringOrNull(other); + String otherStr = asU16BytesOrNull(other); if (otherStr != null) { // Yes it is: concatenate as strings, which are guaranteed byte-like. return new PyString(getString().concat(otherStr), true); } else if (other instanceof PyUnicode) { - // Convert self to PyUnicode and escalate the problem + // Escalate the problem to PyUnicode return decode().__add__(other); } else { // Allow PyObject._basic_add to pick up the pieces or raise informative error @@ -1055,13 +1081,13 @@ final String str_lower() { if (n == 1) { // Special-case single byte string char c = s.charAt(0); - return _isupper(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + return _isupper(c) ? String.valueOf((char) (c ^ SWAP_CASE)) : s; } else { // Copy chars to buffer, converting to lower-case. char[] buf = new char[n]; for (int i = 0; i < n; i++) { char c = s.charAt(i); - buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + buf[i] = _isupper(c) ? (char) (c ^ SWAP_CASE) : c; } return new String(buf); } @@ -1078,13 +1104,13 @@ final String str_upper() { if (n == 1) { // Special-case single byte string char c = s.charAt(0); - return _islower(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + return _islower(c) ? String.valueOf((char) (c ^ SWAP_CASE)) : s; } else { // Copy chars to buffer, converting to upper-case. char[] buf = new char[n]; for (int i = 0; i < n; i++) { char c = s.charAt(i); - buf[i] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + buf[i] = _islower(c) ? (char) (c ^ SWAP_CASE) : c; } return new String(buf); } @@ -1105,12 +1131,12 @@ final String str_title() { if (previous_is_cased) { // Should be lower case if (_isupper(ch)) { - chars[i] = (char)(ch ^ SWAP_CASE); + chars[i] = (char) (ch ^ SWAP_CASE); } } else { // Should be upper case if (_islower(ch)) { - chars[i] = (char)(ch ^ SWAP_CASE); + chars[i] = (char) (ch ^ SWAP_CASE); } } // And this was a letter @@ -1134,13 +1160,13 @@ final String str_swapcase() { if (n == 1) { // Special-case single byte string char c = s.charAt(0); - return _isalpha(c) ? String.valueOf((char)(c ^ SWAP_CASE)) : s; + return _isalpha(c) ? String.valueOf((char) (c ^ SWAP_CASE)) : s; } else { // Copy chars to buffer, converting lower to upper case, upper to lower case. char[] buf = new char[n]; for (int i = 0; i < n; i++) { char c = s.charAt(i); - buf[i] = _isalpha(c) ? (char)(c ^ SWAP_CASE) : c; + buf[i] = _isalpha(c) ? (char) (c ^ SWAP_CASE) : c; } return new String(buf); } @@ -1187,10 +1213,10 @@ public PyObject strip(PyObject stripChars) { final PyObject str_strip(PyObject chars) { if (chars instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_strip(chars); + return ((PyUnicode) decode()).unicode_strip(chars); } else { // It ought to be None, null, some kind of bytes with the buffer API. - String stripChars = asStringNullOrError(chars, "strip"); + String stripChars = asU16BytesNullOrError(chars, "strip"); // Strip specified characters or whitespace if stripChars == null return new PyString(_strip(stripChars), true); } @@ -1207,16 +1233,15 @@ final PyObject str_strip(PyObject chars) { * @return a new String, stripped of the whitespace characters/bytes */ protected final String _strip() { - String s = getString(); // Rightmost non-whitespace - int right = _stripRight(s); + int right = _findRight(); if (right < 0) { // They're all whitespace return ""; } else { // Leftmost non-whitespace character: right known not to be a whitespace - int left = _stripLeft(s, right); - return s.substring(left, right + 1); + int left = _findLeft(right); + return getString().substring(left, right + 1); } } @@ -1238,16 +1263,15 @@ protected final String _strip(String stripChars) { // Divert to the whitespace version return _strip(); } else { - String s = getString(); // Rightmost non-matching character - int right = _stripRight(s, stripChars); + int right = _findRight(stripChars); if (right < 0) { // They all match return ""; } else { // Leftmost non-matching character: right is known not to match - int left = _stripLeft(s, stripChars, right); - return s.substring(left, right + 1); + int left = _findLeft(stripChars, right); + return getString().substring(left, right + 1); } } } @@ -1255,13 +1279,13 @@ protected final String _strip(String stripChars) { /** * Helper for strip, lstrip implementation, when stripping whitespace. * - * @param s string to search (only s[0:right] is searched). * @param right rightmost extent of string search - * @return index of lefttmost non-whitespace character or right if they all are. + * @return index of leftmost non-whitespace character or right if they all are. */ - private static final int _stripLeft(String s, int right) { + protected int _findLeft(int right) { + String s = getString(); for (int left = 0; left < right; left++) { - if (!Character.isWhitespace(s.charAt(left))) { + if (!BaseBytes.isspace((byte) s.charAt(left))) { return left; } } @@ -1272,13 +1296,13 @@ private static final int _stripLeft(String s, int right) { * Helper for strip, lstrip implementation, when stripping specified * characters. * - * @param s string to search (only s[0:right] is searched). * @param stripChars specifies set of characters to strip * @param right rightmost extent of string search * @return index of leftmost character not in stripChars or right if * they all are. */ - private static final int _stripLeft(String s, String stripChars, int right) { + private int _findLeft(String stripChars, int right) { + String s = getString(); for (int left = 0; left < right; left++) { if (stripChars.indexOf(s.charAt(left)) < 0) { return left; @@ -1290,12 +1314,12 @@ private static final int _stripLeft(String s, String stripChars, int right) { /** * Helper for strip, rstrip implementation, when stripping whitespace. * - * @param s string to search. * @return index of rightmost non-whitespace character or -1 if they all are. */ - private static final int _stripRight(String s) { + protected int _findRight() { + String s = getString(); for (int right = s.length(); --right >= 0;) { - if (!Character.isWhitespace(s.charAt(right))) { + if (!BaseBytes.isspace((byte) s.charAt(right))) { return right; } } @@ -1306,11 +1330,11 @@ private static final int _stripRight(String s) { * Helper for strip, rstrip implementation, when stripping specified * characters. * - * @param s string to search. * @param stripChars specifies set of characters to strip * @return index of rightmost character not in stripChars or -1 if they all are. */ - private static final int _stripRight(String s, String stripChars) { + private int _findRight(String stripChars) { + String s = getString(); for (int right = s.length(); --right >= 0;) { if (stripChars.indexOf(s.charAt(right)) < 0) { return right; @@ -1357,10 +1381,10 @@ public PyObject lstrip(PyObject stripChars) { final PyObject str_lstrip(PyObject chars) { if (chars instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_lstrip(chars); + return ((PyUnicode) decode()).unicode_lstrip(chars); } else { // It ought to be None, null, some kind of bytes with the buffer API. - String stripChars = asStringNullOrError(chars, "lstrip"); + String stripChars = asU16BytesNullOrError(chars, "lstrip"); // Strip specified characters or whitespace if stripChars == null return new PyString(_lstrip(stripChars), true); } @@ -1379,7 +1403,7 @@ final PyObject str_lstrip(PyObject chars) { protected final String _lstrip() { String s = getString(); // Leftmost non-whitespace character: cannot exceed length - int left = _stripLeft(s, s.length()); + int left = _findLeft(s.length()); return s.substring(left); } @@ -1403,7 +1427,7 @@ protected final String _lstrip(String stripChars) { } else { String s = getString(); // Leftmost matching character: cannot exceed length - int left = _stripLeft(s, stripChars, s.length()); + int left = _findLeft(stripChars, s.length()); return s.substring(left); } } @@ -1446,10 +1470,10 @@ public PyObject rstrip(PyObject stripChars) { final PyObject str_rstrip(PyObject chars) { if (chars instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_rstrip(chars); + return ((PyUnicode) decode()).unicode_rstrip(chars); } else { // It ought to be None, null, some kind of bytes with the buffer API. - String stripChars = asStringNullOrError(chars, "rstrip"); + String stripChars = asU16BytesNullOrError(chars, "rstrip"); // Strip specified characters or whitespace if stripChars == null return new PyString(_rstrip(stripChars), true); } @@ -1466,15 +1490,14 @@ final PyObject str_rstrip(PyObject chars) { * @return a new String, stripped of the whitespace characters/bytes */ protected final String _rstrip() { - String s = getString(); // Rightmost non-whitespace - int right = _stripRight(s); + int right = _findRight(); if (right < 0) { // They're all whitespace return ""; } else { // Substring up to and including this rightmost non-whitespace - return s.substring(0, right + 1); + return getString().substring(0, right + 1); } } @@ -1496,11 +1519,10 @@ protected final String _rstrip(String stripChars) { // Divert to the whitespace version return _rstrip(); } else { - String s = getString(); // Rightmost non-matching character - int right = _stripRight(s, stripChars); + int right = _findRight(stripChars); // Substring up to and including this rightmost non-matching character (or "") - return s.substring(0, right + 1); + return getString().substring(0, right + 1); } } @@ -1567,10 +1589,10 @@ public PyList split(PyObject sep, int maxsplit) { final PyList str_split(PyObject sepObj, int maxsplit) { if (sepObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_split(sepObj, maxsplit); + return ((PyUnicode) decode()).unicode_split(sepObj, maxsplit); } else { // It ought to be None, null, some kind of bytes with the buffer API. - String sep = asStringNullOrError(sepObj, "split"); + String sep = asU16BytesNullOrError(sepObj, "split"); // Split on specified string or whitespace if sep == null return _split(sep, maxsplit); } @@ -1605,16 +1627,15 @@ protected final PyList _split(String sep, int maxsplit) { } /** - * Helper function for .split, in str and unicode, - * splitting on white space and returning a list of the separated parts. If there are more than - * maxsplit feasible the last element of the list is the remainder of the original - * (this) string. The split sections will be {@link PyUnicode} if this object is a - * PyUnicode. + * Helper function for .split, in str and (when overridden) in + * unicode, splitting on white space and returning a list of the separated parts. + * If there are more than maxsplit feasible splits the last element of the list is + * the remainder of the original (this) string. * * @param maxsplit limit on the number of splits (if >=0) * @return PyList of split sections */ - private PyList splitfields(int maxsplit) { + protected PyList splitfields(int maxsplit) { /* * Result built here is a list of split parts, exactly as required for s.split(None, * maxsplit). If there are to be n splits, there will be n+1 elements in L. @@ -1634,7 +1655,7 @@ private PyList splitfields(int maxsplit) { // Find the next occurrence of non-whitespace while (start < length) { - if (!Character.isWhitespace(s.charAt(start))) { + if (!BaseBytes.isspace((byte) s.charAt(start))) { // Break leaving start pointing at non-whitespace break; } @@ -1652,7 +1673,7 @@ private PyList splitfields(int maxsplit) { } else { // The next segment runs up to the next next whitespace or end for (index = start; index < length; index++) { - if (Character.isWhitespace(s.charAt(index))) { + if (BaseBytes.isspace((byte) s.charAt(index))) { // Break leaving index pointing at whitespace break; } @@ -1818,10 +1839,10 @@ public PyList rsplit(PyObject sep, int maxsplit) { final PyList str_rsplit(PyObject sepObj, int maxsplit) { if (sepObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_rsplit(sepObj, maxsplit); + return ((PyUnicode) decode()).unicode_rsplit(sepObj, maxsplit); } else { // It ought to be None, null, some kind of bytes with the buffer API. - String sep = asStringNullOrError(sepObj, "rsplit"); + String sep = asU16BytesNullOrError(sepObj, "rsplit"); // Split on specified string or whitespace if sep == null return _rsplit(sep, maxsplit); } @@ -1857,16 +1878,15 @@ protected final PyList _rsplit(String sep, int maxsplit) { } /** - * Helper function for .rsplit, in str and unicode, - * splitting on white space and returning a list of the separated parts. If there are more than - * maxsplit feasible the first element of the list is the remainder of the original - * (this) string. The split sections will be {@link PyUnicode} if this object is a - * PyUnicode. + * Helper function for .rsplit, in str and (when overridden) in + * unicode, splitting on white space and returning a list of the separated parts. + * If there are more than maxsplit feasible splits the first element of the list is + * the remainder of the original (this) string. * * @param maxsplit limit on the number of splits (if >=0) * @return PyList of split sections */ - private PyList rsplitfields(int maxsplit) { + protected PyList rsplitfields(int maxsplit) { /* * Result built here (in reverse) is a list of split parts, exactly as required for * s.rsplit(None, maxsplit). If there are to be n splits, there will be n+1 elements. @@ -1886,7 +1906,7 @@ private PyList rsplitfields(int maxsplit) { // Find the next occurrence of non-whitespace (working leftwards) while (end >= 0) { - if (!Character.isWhitespace(s.charAt(end))) { + if (!BaseBytes.isspace((byte) s.charAt(end))) { // Break leaving end pointing at non-whitespace break; } @@ -1904,7 +1924,7 @@ private PyList rsplitfields(int maxsplit) { } else { // The next segment runs back to the next next whitespace or beginning for (index = end; index >= 0; --index) { - if (Character.isWhitespace(s.charAt(index))) { + if (BaseBytes.isspace((byte) s.charAt(index))) { // Break leaving index pointing at whitespace break; } @@ -2009,7 +2029,7 @@ final PyTuple str_partition(PyObject sepObj) { } else { // It ought to be some kind of bytes with the buffer API. - String sep = asStringOrError(sepObj); + String sep = asU16BytesOrError(sepObj); if (sep.length() == 0) { throw Py.ValueError("empty separator"); @@ -2017,8 +2037,8 @@ final PyTuple str_partition(PyObject sepObj) { int index = getString().indexOf(sep); if (index != -1) { - return new PyTuple(fromSubstring(0, index), sepObj, fromSubstring( - index + sep.length(), getString().length())); + return new PyTuple(fromSubstring(0, index), sepObj, + fromSubstring(index + sep.length(), getString().length())); } else { return new PyTuple(this, Py.EmptyString, Py.EmptyString); } @@ -2039,8 +2059,8 @@ final PyTuple unicodePartition(PyObject sepObj) { int index = str.indexOf(sep); if (index != -1) { - return new PyTuple(strObj.fromSubstring(0, index), sepObj, strObj.fromSubstring(index - + sep.length(), str.length())); + return new PyTuple(strObj.fromSubstring(0, index), sepObj, + strObj.fromSubstring(index + sep.length(), str.length())); } else { PyUnicode emptyUnicode = Py.newUnicode(""); return new PyTuple(this, emptyUnicode, emptyUnicode); @@ -2068,7 +2088,7 @@ final PyTuple str_rpartition(PyObject sepObj) { } else { // It ought to be some kind of bytes with the buffer API. - String sep = asStringOrError(sepObj); + String sep = asU16BytesOrError(sepObj); if (sep.length() == 0) { throw Py.ValueError("empty separator"); @@ -2076,8 +2096,8 @@ final PyTuple str_rpartition(PyObject sepObj) { int index = getString().lastIndexOf(sep); if (index != -1) { - return new PyTuple(fromSubstring(0, index), sepObj, fromSubstring( - index + sep.length(), getString().length())); + return new PyTuple(fromSubstring(0, index), sepObj, + fromSubstring(index + sep.length(), getString().length())); } else { return new PyTuple(Py.EmptyString, Py.EmptyString, this); } @@ -2098,8 +2118,8 @@ final PyTuple unicodeRpartition(PyObject sepObj) { int index = str.lastIndexOf(sep); if (index != -1) { - return new PyTuple(strObj.fromSubstring(0, index), sepObj, strObj.fromSubstring(index - + sep.length(), str.length())); + return new PyTuple(strObj.fromSubstring(0, index), sepObj, + strObj.fromSubstring(index + sep.length(), str.length())); } else { PyUnicode emptyUnicode = Py.newUnicode(""); return new PyTuple(emptyUnicode, emptyUnicode, this); @@ -2170,7 +2190,7 @@ protected PyString fromSubstring(int begin, int end) { * * @param sub substring to find. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int index(PyObject sub) { return str_index(sub, null, null); @@ -2184,7 +2204,7 @@ public int index(PyObject sub) { * @param sub substring to find. * @param start start of slice. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int index(PyObject sub, PyObject start) throws PyException { return str_index(sub, start, null); @@ -2201,7 +2221,7 @@ public int index(PyObject sub, PyObject start) throws PyException { * @param start start of slice. * @param end end of slice. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int index(PyObject sub, PyObject start, PyObject end) throws PyException { return checkIndex(str_index(sub, start, end)); @@ -2236,7 +2256,7 @@ final int str_index(PyObject subObj, PyObject start, PyObject end) { * * @param sub substring to find. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int rindex(PyObject sub) { return str_rindex(sub, null, null); @@ -2250,7 +2270,7 @@ public int rindex(PyObject sub) { * @param sub substring to find. * @param start start of slice. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int rindex(PyObject sub, PyObject start) throws PyException { return str_rindex(sub, start, null); @@ -2267,7 +2287,7 @@ public int rindex(PyObject sub, PyObject start) throws PyException { * @param start start of slice. * @param end end of slice. * @return index of sub in this object. - * @throws PyException(ValueError) if not found. + * @throws PyException {@code ValueError} if not found. */ public int rindex(PyObject sub, PyObject start, PyObject end) throws PyException { return checkIndex(str_rindex(sub, start, end)); @@ -2303,7 +2323,7 @@ final int str_rindex(PyObject subObj, PyObject start, PyObject end) { * * @param index to check * @return index if non-negative - * @throws PyException(ValueError) if not found + * @throws PyException {@code ValueError} if not found */ protected final int checkIndex(int index) throws PyException { if (index >= 0) { @@ -2371,10 +2391,10 @@ public int count(String sub, PyObject start, PyObject end) { final int str_count(PyObject subObj, PyObject start, PyObject end) { if (subObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_count(subObj, start, end); + return asUnicode(start, end).unicode_count(subObj, null, null); } else { // It ought to be some kind of bytes with the buffer API. - String sub = asStringOrError(subObj); + String sub = asU16BytesOrError(subObj); return _count(sub, start, end); } } @@ -2486,10 +2506,11 @@ public int find(String sub, PyObject start, PyObject end) { final int str_find(PyObject subObj, PyObject start, PyObject end) { if (subObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_find(subObj, start, end); + // XXX Questionable: return is a Unicode character index not byte index + return ((PyUnicode) decode()).unicode_find(subObj, start, end); } else { - // It ought to be some kind of bytes with the buffer API. - String sub = asStringOrError(subObj); + // It ought to be a bytes-like object. + String sub = asU16BytesOrError(subObj); return _find(sub, start, end); } } @@ -2591,10 +2612,10 @@ public int rfind(String sub, PyObject start, PyObject end) { final int str_rfind(PyObject subObj, PyObject start, PyObject end) { if (subObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_rfind(subObj, start, end); + return ((PyUnicode) decode()).unicode_rfind(subObj, start, end); } else { // It ought to be some kind of bytes with the buffer API. - String sub = asStringOrError(subObj); + String sub = asU16BytesOrError(subObj); return _rfind(sub, start, end); } } @@ -2899,7 +2920,8 @@ private BigInteger asciiToBigInteger(int base, boolean isLong) { } // if the base >= 22, then an 'l' or 'L' is a digit! - if (isLong && base < 22 && e > b && (str.charAt(e - 1) == 'L' || str.charAt(e - 1) == 'l')) { + if (isLong && base < 22 && e > b + && (str.charAt(e - 1) == 'L' || str.charAt(e - 1) == 'l')) { e--; } @@ -2933,11 +2955,11 @@ public int atoi(int base) { } return bi.intValue(); } catch (NumberFormatException exc) { - throw Py.ValueError("invalid literal for int() with base " + base + ": '" + getString() - + "'"); + throw Py.ValueError( + "invalid literal for int() with base " + base + ": '" + getString() + "'"); } catch (StringIndexOutOfBoundsException exc) { - throw Py.ValueError("invalid literal for int() with base " + base + ": '" + getString() - + "'"); + throw Py.ValueError( + "invalid literal for int() with base " + base + ": '" + getString() + "'"); } } @@ -2962,12 +2984,12 @@ public PyLong atol(int base) { throw Py.UnicodeEncodeError("decimal", "codec can't encode character", 0, 0, "invalid decimal Unicode string"); } else { - throw Py.ValueError("invalid literal for long() with base " + base + ": '" - + getString() + "'"); + throw Py.ValueError( + "invalid literal for long() with base " + base + ": '" + getString() + "'"); } } catch (StringIndexOutOfBoundsException exc) { - throw Py.ValueError("invalid literal for long() with base " + base + ": '" - + getString() + "'"); + throw Py.ValueError( + "invalid literal for long() with base " + base + ": '" + getString() + "'"); } } @@ -3082,7 +3104,7 @@ public String expandtabs(int tabsize) { @ExposedMethod(defaults = "8", doc = BuiltinDocs.str_expandtabs_doc) final String str_expandtabs(int tabsize) { String s = getString(); - StringBuilder buf = new StringBuilder((int)(s.length() * 1.5)); + StringBuilder buf = new StringBuilder((int) (s.length() * 1.5)); char[] chars = s.toCharArray(); int n = chars.length; int position = 0; @@ -3120,11 +3142,11 @@ final String str_capitalize() { char[] buf = new char[n]; // At least one byte: if lower convert to upper case. char c = s.charAt(0); - buf[0] = _islower(c) ? (char)(c ^ SWAP_CASE) : c; + buf[0] = _islower(c) ? (char) (c ^ SWAP_CASE) : c; // Copy the rest, converting to lower case. for (int i = 1; i < n; i++) { c = s.charAt(i); - buf[i] = _isupper(c) ? (char)(c ^ SWAP_CASE) : c; + buf[i] = _isupper(c) ? (char) (c ^ SWAP_CASE) : c; } return new String(buf); } @@ -3162,11 +3184,11 @@ public PyString replace(PyObject oldPiece, PyObject newPiece, int count) { final PyString str_replace(PyObject oldPieceObj, PyObject newPieceObj, int count) { if (oldPieceObj instanceof PyUnicode || newPieceObj instanceof PyUnicode) { // Promote the problem to a Unicode one - return ((PyUnicode)decode()).unicode_replace(oldPieceObj, newPieceObj, count); + return ((PyUnicode) decode()).unicode_replace(oldPieceObj, newPieceObj, count); } else { // Neither is a PyUnicode: both ought to be some kind of bytes with the buffer API. - String oldPiece = asStringOrError(oldPieceObj); - String newPiece = asStringOrError(newPieceObj); + String oldPiece = asU16BytesOrError(oldPieceObj); + String newPiece = asU16BytesOrError(newPieceObj); return _replace(oldPiece, newPiece, count); } } @@ -3234,7 +3256,7 @@ final PyString str_join(PyObject obj) { if (seqLen == 1) { item = seq.pyget(0); if (item.getType() == PyString.TYPE || item.getType() == PyUnicode.TYPE) { - return (PyString)item; + return (PyString) item; } } @@ -3260,20 +3282,20 @@ final PyString str_join(PyObject obj) { if (i != 0) { size += sepLen; } - size += ((PyString)item).getString().length(); + size += ((PyString) item).getString().length(); if (size > Integer.MAX_VALUE) { throw Py.OverflowError("join() result is too long for a Python string"); } } // Catenate everything - StringBuilder buf = new StringBuilder((int)size); + StringBuilder buf = new StringBuilder((int) size); for (i = 0; i < seqLen; i++) { item = seq.pyget(i); if (i != 0) { buf.append(getString()); } - buf.append(((PyString)item).getString()); + buf.append(((PyString) item).getString()); } return new PyString(buf.toString(), true); // Guaranteed to be byte-like } @@ -3296,7 +3318,7 @@ final PyUnicode unicodeJoin(PyObject obj) { if (seqLen == 1) { item = seq.pyget(0); if (item.getType() == PyUnicode.TYPE) { - return (PyUnicode)item; + return (PyUnicode) item; } } @@ -3305,7 +3327,7 @@ final PyUnicode unicodeJoin(PyObject obj) { if (this instanceof PyUnicode) { sep = getString(); } else { - sep = ((PyUnicode)decode()).getString(); + sep = ((PyUnicode) decode()).getString(); // In case decode()'s codec mutated seq seqLen = seq.__len__(); } @@ -3320,15 +3342,16 @@ final PyUnicode unicodeJoin(PyObject obj) { item = seq.pyget(i); // Convert item to Unicode if (!(item instanceof PyString)) { - throw Py.TypeError(String.format("sequence item %d: expected string or Unicode," - + " %.80s found", i, item.getType().fastGetName())); + throw Py.TypeError(String.format( + "sequence item %d: expected string or Unicode," + " %.80s found", i, + item.getType().fastGetName())); } if (!(item instanceof PyUnicode)) { - item = ((PyString)item).decode(); + item = ((PyString) item).decode(); // In case decode()'s codec mutated seq seqLen = seq.__len__(); } - itemString = ((PyUnicode)item).getString(); + itemString = ((PyUnicode) item).getString(); if (i != 0) { size += sepLen; @@ -3352,7 +3375,7 @@ final PyUnicode unicodeJoin(PyObject obj) { * false. */ public boolean startswith(PyObject prefix) { - return str_startswith(prefix, null, null); + return startswith(prefix, null, null); } /** @@ -3367,7 +3390,7 @@ public boolean startswith(PyObject prefix) { * false. */ public boolean startswith(PyObject prefix, PyObject start) { - return str_startswith(prefix, start, null); + return startswith(prefix, start, null); } /** @@ -3389,28 +3412,49 @@ public boolean startswith(PyObject prefix, PyObject start, PyObject end) { @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.str_startswith_doc) final boolean str_startswith(PyObject prefix, PyObject startObj, PyObject endObj) { + int[] indices = translateIndices(startObj, endObj); int start = indices[0]; int sliceLen = indices[1] - start; if (!(prefix instanceof PyTuple)) { - // It ought to be PyUnicode or some kind of bytes with the buffer API. - String s = asUTF16StringOrError(prefix); - // If s is non-BMP, and this is a PyString (bytes), result will correctly be false. - return sliceLen >= s.length() && getString().startsWith(s, start); + if (prefix instanceof PyUnicode) { + // Promote to a unicode problem on the decoded slice + return asUnicode(startObj, endObj).unicode_startswith(prefix, null, null); + } else { + // It ought to be a bytes-like object. + String s = asU16BytesOrError(prefix); + return sliceLen >= s.length() && getString().startsWith(s, start); + } } else { - // Loop will return true if this slice starts with any prefix in the tuple - for (PyObject prefixObj : ((PyTuple)prefix).getArray()) { - // It ought to be PyUnicode or some kind of bytes with the buffer API. - String s = asUTF16StringOrError(prefixObj); - // If s is non-BMP, and this is a PyString (bytes), result will correctly be false. - if (sliceLen >= s.length() && getString().startsWith(s, start)) { - return true; + // It's a tuple so we have to iterate through the members. + PyObject[] prefixes = ((PyTuple) prefix).getArray(); + String string = getString(); + + // Test with only the bytes prefixes first and save the unicode ones + int unicodeCount = 0; + for (PyObject o : prefixes) { + if (o instanceof PyUnicode) { + // Pack the unicode prefixes to the start of the array without trying them + prefixes[unicodeCount++] = o; + } else { + // It ought to be a bytes-like object. + String s = asU16BytesOrError(o); + if (sliceLen >= s.length() && string.startsWith(s, start)) { + return true; + } } } - // None matched - return false; + + if (unicodeCount == 0) { + // Only bytes prefixes given and nothing matched + return false; + } else { + // There were unicode prefixes: test the decoded slice for them. + PyTuple t = new PyTuple(Arrays.copyOf(prefixes, unicodeCount)); + return asUnicode(startObj, endObj).unicode_startswith(t, null, null); + } } } @@ -3423,7 +3467,7 @@ final boolean str_startswith(PyObject prefix, PyObject startObj, PyObject endObj * false. */ public boolean endswith(PyObject suffix) { - return str_endswith(suffix, null, null); + return endswith(suffix, null, null); } /** @@ -3438,7 +3482,7 @@ public boolean endswith(PyObject suffix) { * false. */ public boolean endswith(PyObject suffix, PyObject start) { - return str_endswith(suffix, start, null); + return endswith(suffix, start, null); } /** @@ -3462,26 +3506,45 @@ public boolean endswith(PyObject suffix, PyObject start, PyObject end) { final boolean str_endswith(PyObject suffix, PyObject startObj, PyObject endObj) { int[] indices = translateIndices(startObj, endObj); - String substr = getString().substring(indices[0], indices[1]); if (!(suffix instanceof PyTuple)) { - // It ought to be PyUnicode or some kind of bytes with the buffer API. - String s = asUTF16StringOrError(suffix); - // If s is non-BMP, and this is a PyString (bytes), result will correctly be false. - return substr.endsWith(s); + if (suffix instanceof PyUnicode) { + // Promote to a unicode problem on the decoded slice + return asUnicode(startObj, endObj).unicode_endswith(suffix, null, null); + } else { + // It ought to be a bytes-like object. + String s = asU16BytesOrError(suffix); + return getString().substring(indices[0], indices[1]).endsWith(s); + } } else { - // Loop will return true if this slice ends with any suffix in the tuple - for (PyObject suffixObj : ((PyTuple)suffix).getArray()) { - // It ought to be PyUnicode or some kind of bytes with the buffer API. - String s = asUTF16StringOrError(suffixObj); - // If s is non-BMP, and this is a PyString (bytes), result will correctly be false. - if (substr.endsWith(s)) { - return true; + // It's a tuple so we have to iterate through the members. + PyObject[] suffixes = ((PyTuple) suffix).getArray(); + String string = getString().substring(indices[0], indices[1]); + + // Test with only the bytes suffixes first and save the unicode ones + int unicodeCount = 0; + for (PyObject o : suffixes) { + if (o instanceof PyUnicode) { + // Pack the unicode suffixes to the start of the array without trying them + suffixes[unicodeCount++] = o; + } else { + // It ought to be a bytes-like object. + String s = asU16BytesOrError(o); + if (string.endsWith(s)) { + return true; + } } } - // None matched - return false; + + if (unicodeCount == 0) { + // Only bytes suffixes given and nothing matched + return false; + } else { + // There were unicode suffixes: test the decoded slice for them. + PyTuple t = new PyTuple(Arrays.copyOf(suffixes, unicodeCount)); + return asUnicode(startObj, endObj).unicode_endswith(t, null, null); + } } } @@ -3606,8 +3669,8 @@ public String translate(String table, String deletechars) { @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.str_translate_doc) final String str_translate(PyObject tableObj, PyObject deletecharsObj) { // Accept anythiong withthe buffer API or null - String table = asStringNullOrError(tableObj, null); - String deletechars = asStringNullOrError(deletecharsObj, null); + String table = asU16BytesNullOrError(tableObj, null); + String deletechars = asU16BytesNullOrError(deletecharsObj, null); return _translate(table, deletechars); } @@ -3676,7 +3739,7 @@ final boolean str_islower() { private boolean _islower(char ch) { if (ch < 256) { - return BaseBytes.islower((byte)ch); + return BaseBytes.islower((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3711,7 +3774,7 @@ final boolean str_isupper() { private boolean _isupper(char ch) { if (ch < 256) { - return BaseBytes.isupper((byte)ch); + return BaseBytes.isupper((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3742,7 +3805,7 @@ final boolean str_isalpha() { private boolean _isalpha(char ch) { if (ch < 256) { - return BaseBytes.isalpha((byte)ch); + return BaseBytes.isalpha((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3774,7 +3837,7 @@ final boolean str_isalnum() { private boolean _isalnum(char ch) { // This is now entirely compatible with CPython, as long as only bytes are stored. if (ch < 256) { - return BaseBytes.isalnum((byte)ch); + return BaseBytes.isalnum((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3819,7 +3882,7 @@ final boolean str_isdigit() { private boolean _isdigit(char ch) { if (ch < 256) { - return BaseBytes.isdigit((byte)ch); + return BaseBytes.isdigit((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3896,7 +3959,7 @@ final boolean str_isspace() { private boolean _isspace(char ch) { if (ch < 256) { - return BaseBytes.isspace((byte)ch); + return BaseBytes.isspace((byte) ch); } else { // This is an internal error. Really, the test should be unnecessary. throw new java.lang.IllegalArgumentException("non-byte character in PyString"); @@ -3984,9 +4047,9 @@ final PyObject str_format(PyObject[] args, String[] keywords) { * Implements PEP-3101 {}-formatting methods str.format() and * unicode.format(). When called with enclosingIterator == null, this * method takes this object as its formatting string. The method is also called (calls itself) - * to deal with nested formatting sepecifications. In that case, enclosingIterator + * to deal with nested formatting specifications. In that case, enclosingIterator * is a {@link MarkupIterator} on this object and value is a substring of this - * object needing recursive transaltion. + * object needing recursive translation. * * @param args to be interpolated into the string * @param keywords for the trailing args @@ -4039,7 +4102,7 @@ protected String buildFormattedString(PyObject[] args, String[] keywords, // Check for "{}".format(u"abc") if (fieldObj instanceof PyUnicode && !(this instanceof PyUnicode)) { // Down-convert to PyString, at the risk of raising UnicodeEncodingError - fieldObj = ((PyUnicode)fieldObj).__str__(); + fieldObj = ((PyUnicode) fieldObj).__str__(); } // The format_spec may be simple, or contained nested replacement fields. @@ -4107,11 +4170,11 @@ private PyObject getFieldObject(String fieldName, boolean bytes, PyObject[] args Object key = chunk.value; if (chunk.is_attr) { // key must be a String - obj = obj.__getattr__((String)key); + obj = obj.__getattr__((String) key); } else { if (key instanceof Integer) { // Can this happen? - obj = obj.__getitem__(((Integer)key).intValue()); + obj = obj.__getitem__(((Integer) key).intValue()); } else { obj = obj.__getitem__(new PyString(key.toString())); } @@ -4174,7 +4237,7 @@ final PyObject str___format__(PyObject formatSpec) { * * @param spec a parsed PEP-3101 format specification. * @return a formatter ready to use, or null if the type is not a string format type. - * @throws PyException(ValueError) if the specification is faulty. + * @throws PyException {@code ValueError} if the specification is faulty. */ @SuppressWarnings("fallthrough") static TextFormatter prepareFormatter(Spec spec) throws PyException { @@ -4253,6 +4316,50 @@ protected String unsupportedopMessage(String op, PyObject o2) { } return super.unsupportedopMessage(op, o2); } + + @Override + public char charAt(int index) { + return string.charAt(index); + } + + @Override + public int length() { + return string.length(); + } + + @Override + public CharSequence subSequence(int start, int end) { + return string.subSequence(start, end); + } + + /** + * Decode this str object to a unicode, like + * __unicode__() but without the possibility it will be overridden. + * + * @return this as a unicode using the default encoding. + */ + private PyUnicode asUnicode() { + return new PyUnicode(this); + } + + /** + * Decode a slice of this str object to a unicode, using Python slice + * semantics and the default encoding. This supports the many library methods that accept + * slicing as part of the API, in the case where the calculation must be promoted due to a + * unicode argument. + * + * @param startObj start index (or null or None) + * @param endObj end index (or null or None) + * @return the slice as a unicode using the default encoding. + */ + private PyUnicode asUnicode(PyObject startObj, PyObject endObj) { + if (startObj == null && endObj == null) { + return asUnicode(); + } else { + int[] indices = translateIndices(startObj, endObj); + return new PyUnicode(fromSubstring(indices[0], indices[1])); + } + } } @@ -4348,7 +4455,7 @@ int getNumber() { if (c == '*') { PyObject o = getarg(); if (o instanceof PyInteger) { - return ((PyInteger)o).getValue(); + return ((PyInteger) o).getValue(); } throw Py.TypeError("* wants int"); } else { @@ -4469,7 +4576,7 @@ private PyString asText(PyObject arg) { if (arg instanceof PyUnicode) { // arg is already acceptable. needUnicode = true; - return (PyUnicode)arg; + return (PyUnicode) arg; } else if (needUnicode) { // The string being built is unicode, so we need that version of the arg. @@ -4477,7 +4584,7 @@ private PyString asText(PyObject arg) { } else if (arg instanceof PyString) { // The string being built is not unicode, so arg is already acceptable. - return (PyString)arg; + return (PyString) arg; } else { // The string being built is not unicode, so use __str__ to get a PyString. @@ -4508,8 +4615,11 @@ public PyString format(PyObject args) { } else { // Not a tuple, but possibly still some kind of container: use special argIndex values. argIndex = -1; - if (args instanceof PyDictionary || args instanceof PyStringMap - || (!(args instanceof PySequence) && args.__findattr__("__getitem__") != null)) { + if (args instanceof AbstractDict || (!(args instanceof PySequence) && + // See issue 2511: __getitem__ should be looked up directly in the dict, rather + // than going through another __getattr__ call. We achieve this by using + // object___findattr__ instead of generic __findattr__. + args.object___findattr__("__getitem__".intern()) != null)) { dict = args; argIndex = -3; } @@ -4707,7 +4817,7 @@ public PyString format(PyObject args) { needUnicode = true; fi.setBytes(false); } - fi.format(((PyString)arg).getString().codePointAt(0)); + fi.format(((PyString) arg).getString().codePointAt(0)); } } else { @@ -4716,14 +4826,14 @@ public PyString format(PyObject args) { // We have to check what we got back. if (argAsNumber instanceof PyInteger) { - fi.format(((PyInteger)argAsNumber).getValue()); + fi.format(((PyInteger) argAsNumber).getValue()); } else if (argAsNumber instanceof PyLong) { - fi.format(((PyLong)argAsNumber).getValue()); + fi.format(((PyLong) argAsNumber).getValue()); } else { // It couldn't be converted, raise the error here - throw Py.TypeError("%" + spec.type - + " format: a number is required, not " - + arg.getType().fastGetName()); + throw Py.TypeError( + "%" + spec.type + " format: a number is required, not " + + arg.getType().fastGetName()); } } @@ -4746,11 +4856,11 @@ public PyString format(PyObject args) { // We have to check what we got back.. if (argAsFloat instanceof PyFloat) { - ff.format(((PyFloat)argAsFloat).getValue()); + ff.format(((PyFloat) argAsFloat).getValue()); } else { // It couldn't be converted, raise the error here - throw Py.TypeError("float argument required, not " - + arg.getType().fastGetName()); + throw Py.TypeError( + "float argument required, not " + arg.getType().fastGetName()); } break; diff --git a/src/org/python/core/PyStringDerived.java b/src/org/python/core/PyStringDerived.java index cc2f6f052..f805636a8 100644 --- a/src/org/python/core/PyStringDerived.java +++ b/src/org/python/core/PyStringDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java index 60df54a48..ea3dad3b1 100644 --- a/src/org/python/core/PyStringMap.java +++ b/src/org/python/core/PyStringMap.java @@ -13,6 +13,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.python.core.AbstractDict.ValuesIter; +import org.python.core.AbstractDict.KeysIter; +import org.python.core.AbstractDict.ItemsIter; import org.python.core.PyMapSet.PySetIter; import org.python.expose.ExposedClassMethod; import org.python.expose.ExposedMethod; @@ -266,7 +269,7 @@ public int __cmp__(PyObject other) { @ExposedMethod(type = MethodType.CMP, doc = BuiltinDocs.dict___cmp___doc) final int stringmap___cmp__(PyObject other) { - if (!(other instanceof PyStringMap || other instanceof PyDictionary)) { + if (!(other instanceof AbstractDict)) { return -2; } int an = __len__(); @@ -278,12 +281,7 @@ final int stringmap___cmp__(PyObject other) { return 1; } PyList akeys = keys(); - PyList bkeys = null; - if (other instanceof PyStringMap) { - bkeys = ((PyStringMap)other).keys(); - } else { - bkeys = ((PyDictionary)other).keys(); - } + PyList bkeys = ((AbstractDict) other).keys(); akeys.sort(); bkeys.sort(); for (int i = 0; i < bn; i++) { @@ -639,9 +637,10 @@ public PyList keys() { @ExposedMethod(doc = BuiltinDocs.dict_keys_doc) final PyList stringmap_keys() { - PyObject[] keyArray = new PyObject[table.size()]; + Object[] keys = table.keySet().toArray(); + PyObject[] keyArray = new PyObject[keys.length]; int i = 0; - for (Object key : table.keySet()) { + for (Object key : keys) { keyArray[i++] = keyToPy(key); } return new PyList(keyArray); @@ -668,7 +667,7 @@ public PyObject iteritems() { @ExposedMethod(doc = BuiltinDocs.dict_iteritems_doc) final PyObject stringmap_iteritems() { - return new ItemsIter(table.entrySet()); + return new StringMapItemsIter(table.entrySet()); } /** @@ -682,7 +681,7 @@ public PyObject iterkeys() { final PyObject stringmap_iterkeys() { /* Python allows one to change the dict while iterating over it, including deletion. Java does not. Can we resolve with CHM? */ - return new KeysIter(table.keySet()); + return new StringMapKeysIter(table.keySet()); } /** @@ -717,63 +716,50 @@ public boolean isSequenceType() { return false; } - private abstract class StringMapIter extends PyIterator { - - protected final Iterator iterator; + private class StringMapValuesIter extends ValuesIter { - private final int size; - - public StringMapIter(Collection c) { - iterator = c.iterator(); - size = c.size(); + public StringMapValuesIter(Collection c) { + super(c); } @Override public PyObject __iternext__() { - if (table.size() != size) { - throw Py.RuntimeError("dictionary changed size during iteration"); - } + check(table.size()); if (!iterator.hasNext()) { return null; } - return stringMapNext(); - } - - protected abstract PyObject stringMapNext(); - } - - private class StringMapValuesIter extends StringMapIter { - - public StringMapValuesIter(Collection c) { - super(c); - } - - @Override - public PyObject stringMapNext() { return iterator.next(); } } - private class KeysIter extends StringMapIter { + private class StringMapKeysIter extends KeysIter { - public KeysIter(Set s) { + public StringMapKeysIter(Set s) { super(s); } @Override - protected PyObject stringMapNext() { + public PyObject __iternext__() { + check(table.size()); + if (!iterator.hasNext()) { + return null; + } return keyToPy(iterator.next()); } } - private class ItemsIter extends StringMapIter> { + private class StringMapItemsIter extends ItemsIter { - public ItemsIter(Set> s) { + public StringMapItemsIter(Set> s) { super(s); } @Override - public PyObject stringMapNext() { + public PyObject __iternext__() { + check(table.size()); + if (!iterator.hasNext()) { + return null; + } return itemTuple(iterator.next()); } } diff --git a/src/org/python/core/PySuperDerived.java b/src/org/python/core/PySuperDerived.java index cc51289ae..3ec2163d8 100644 --- a/src/org/python/core/PySuperDerived.java +++ b/src/org/python/core/PySuperDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PySyntaxError.java b/src/org/python/core/PySyntaxError.java index 519a30655..9b580ebdf 100644 --- a/src/org/python/core/PySyntaxError.java +++ b/src/org/python/core/PySyntaxError.java @@ -16,17 +16,15 @@ public class PySyntaxError extends PyException { String filename; - public PySyntaxError(String s, int line, int column, String text, - String filename) + public PySyntaxError(String s, int line, int column, String text, String filename) { super(Py.SyntaxError); - //XXX: null text causes Java error, though I bet I'm not supposed to - // get null text. + //XXX: null text causes Java error, though I bet I'm not supposed to get null text. if (text == null) { text = ""; } PyObject[] tmp = new PyObject[] { - new PyString(filename), new PyInteger(line), + Py.fileSystemEncode(filename), new PyInteger(line), new PyInteger(column), new PyString(text) }; diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java index 9d710e98f..28c7fc2fc 100644 --- a/src/org/python/core/PySystemState.java +++ b/src/org/python/core/PySystemState.java @@ -13,10 +13,8 @@ import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; -import java.security.AccessControlException; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -32,8 +30,10 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import jnr.posix.util.Platform; -import com.carrotsearch.sizeof.RamUsageEstimator; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.python.Version; import org.python.core.adapter.ClassicPyObjectAdapter; @@ -45,28 +45,32 @@ import org.python.modules.Setup; import org.python.util.Generic; +import com.carrotsearch.sizeof.RamUsageEstimator; + +import jnr.posix.util.Platform; + +import static org.python.core.RegistryKey.*; + + /** * The "sys" module. */ // xxx Many have lamented, this should really be a module! // but it will require some refactoring to see this wish come true. -public class PySystemState extends PyObject implements AutoCloseable, - ClassDictInit, Closeable, Traverseproc { +public class PySystemState extends PyObject + implements AutoCloseable, ClassDictInit, Closeable, Traverseproc { + + private static final Logger logger = Logger.getLogger("org.python.core"); - public static final String PYTHON_CACHEDIR = "python.cachedir"; - public static final String PYTHON_CACHEDIR_SKIP = "python.cachedir.skip"; - public static final String PYTHON_CONSOLE_ENCODING = "python.console.encoding"; - public static final String PYTHON_IO_ENCODING = "python.io.encoding"; - public static final String PYTHON_IO_ERRORS = "python.io.errors"; - protected static final String CACHEDIR_DEFAULT_NAME = "cachedir"; + private static final String CACHEDIR_DEFAULT_NAME = ".jython_cache"; public static final String JYTHON_JAR = "jython.jar"; public static final String JYTHON_DEV_JAR = "jython-dev.jar"; public static final PyString version = new PyString(Version.getVersion()); - public static final PyTuple subversion = new PyTuple(new PyString("Jython"), Py.newString(""), - Py.newString("")); + public static final PyTuple subversion = + new PyTuple(new PyString("Jython"), Py.newString(""), Py.newString("")); public static final int hexversion = ((Version.PY_MAJOR_VERSION << 24) | (Version.PY_MINOR_VERSION << 16) | (Version.PY_MICRO_VERSION << 8) @@ -82,26 +86,26 @@ public class PySystemState extends PyObject implements AutoCloseable, public final static PyString float_repr_style = Py.newString("short"); + /** Nominal Jython file system encoding (as sys.getfilesystemencoding()) */ + static final PyString FILE_SYSTEM_ENCODING = Py.newString("utf-8"); + public static boolean py3kwarning = false; public final static Class flags = Options.class; - public final static PyTuple _mercurial = new PyTuple( - Py.newString("Jython"), - Py.newString(Version.getHGIdentifier()), - Py.newString(Version.getHGVersion())); - /** - * The copyright notice for this release. - */ + public final static PyTuple _mercurial = new PyTuple(Py.newString("Jython"), + Py.newString(Version.getHGIdentifier()), Py.newString(Version.getHGVersion())); - public static final PyObject copyright = Py.newString( - "Copyright (c) 2000-2016 Jython Developers.\n" + "All rights reserved.\n\n" + - "Copyright (c) 2000 BeOpen.com.\n" + "All Rights Reserved.\n\n" + - "Copyright (c) 2000 The Apache Software Foundation.\n" + "All rights reserved.\n\n" + - "Copyright (c) 1995-2000 Corporation for National Research Initiatives.\n" - + "All Rights Reserved.\n\n" + - "Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n" - + "All Rights Reserved."); + /** The copyright notice for this release. */ + public static final PyObject copyright = + Py.newString("Copyright (c) 2000-2017 Jython Developers.\n" + "All rights reserved.\n\n" + + "Copyright (c) 2000 BeOpen.com.\n" + "All Rights Reserved.\n\n" + + "Copyright (c) 2000 The Apache Software Foundation.\n" + + "All rights reserved.\n\n" + + "Copyright (c) 1995-2000 Corporation for National Research Initiatives.\n" + + "All Rights Reserved.\n\n" + + "Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.\n" + + "All Rights Reserved."); private static Map builtinNames; public static PyTuple builtin_module_names = null; @@ -109,13 +113,26 @@ public class PySystemState extends PyObject implements AutoCloseable, public static PackageManager packageManager; private static File cachedir; - private static PyList defaultPath; - private static PyList defaultArgv; - private static PyObject defaultExecutable; + private static PyList defaultPath; // list of bytes or unicode + private static PyList defaultArgv; // list of bytes or unicode + private static PyObject defaultExecutable; // bytes or unicode or None public static Properties registry; // = init_registry(); + /** + * A string giving the site-specific directory prefix where the platform independent Python + * files are installed; by default, this is based on the property python.home or + * the location of the Jython JAR. The main collection of Python library modules is installed in + * the directory prefix/Lib. This object should contain bytes in the file system + * encoding for consistency with use in the standard library (see sysconfig.py). + */ public static PyObject prefix; - public static PyObject exec_prefix = Py.EmptyString; + /** + * A string giving the site-specific directory prefix where the platform-dependent Python files + * are installed; by default, this is the same as {@link #exec_prefix}. This object should + * contain bytes in the file system encoding for consistency with use in the standard library + * (see sysconfig.py). + */ + public static PyObject exec_prefix; public static final PyString byteorder = new PyString("big"); public static final int maxint = Integer.MAX_VALUE; @@ -134,7 +151,7 @@ public class PySystemState extends PyObject implements AutoCloseable, public PyList warnoptions = new PyList(); public PyObject builtins; - private static PyObject defaultPlatform = new PyString("java"); + private static PyObject defaultPlatform = new PyShadowString("java", getNativePlatform()); public PyObject platform = defaultPlatform; public PyList meta_path; @@ -170,9 +187,6 @@ public class PySystemState extends PyObject implements AutoCloseable, private codecs.CodecState codecState; - /** true when a SystemRestart is triggered. */ - public boolean _systemRestart = false; - /** Whether bytecode should be written to disk on import. */ public boolean dont_write_bytecode = false; @@ -197,8 +211,8 @@ public PySystemState() { importLock = new ReentrantLock(); syspathJavaLoader = new SyspathJavaLoader(imp.getParentClassLoader()); - argv = (PyList)defaultArgv.repeat(1); - path = (PyList)defaultPath.repeat(1); + argv = (PyList) defaultArgv.repeat(1); + path = (PyList) defaultPath.repeat(1); path.append(Py.newString(JavaImporter.JAVA_IMPORT_PATH_ENTRY)); path.append(Py.newString(ClasspathPyImporter.PYCLASSPATH_PREFIX)); executable = defaultExecutable; @@ -215,7 +229,7 @@ public PySystemState() { currentWorkingDir = new File("").getAbsolutePath(); dont_write_bytecode = Options.dont_write_bytecode; - py3kwarning = Options.py3k_warning; + py3kwarning = Options.py3k_warning; // XXX why here if static? // Set up the initial standard ins and outs String mode = Options.unbuffered ? "b" : ""; int buffering = Options.unbuffered ? 0 : 1; @@ -236,12 +250,17 @@ public PySystemState() { __dict__.__setitem__("displayhook", __displayhook__); __dict__.__setitem__("excepthook", __excepthook__); + logger.config("sys module instance created"); } public static void classDictInit(PyObject dict) { // XXX: Remove bean accessors for settrace/profile that we don't want dict.__setitem__("trace", null); dict.__setitem__("profile", null); + dict.__setitem__("windowsversion", null); + if (!System.getProperty("os.name").startsWith("Windows")) { + dict.__setitem__("getwindowsversion", null); + } } void reload() throws PyIgnoreMethodTag { @@ -249,39 +268,39 @@ void reload() throws PyIgnoreMethodTag { } private static void checkReadOnly(String name) { - if (name == "__dict__" || name == "__class__" || name == "registry" - || name == "exec_prefix" || name == "packageManager") { + if (name == "__dict__" || name == "__class__" || name == "registry" || name == "exec_prefix" + || name == "packageManager") { throw Py.TypeError("readonly attribute"); } } private static void checkMustExist(String name) { - if (name == "__dict__" || name == "__class__" || name == "registry" - || name == "exec_prefix" || name == "platform" || name == "packageManager" - || name == "builtins" || name == "warnoptions") { + if (name == "__dict__" || name == "__class__" || name == "registry" || name == "exec_prefix" + || name == "platform" || name == "packageManager" || name == "builtins" + || name == "warnoptions") { throw Py.TypeError("readonly attribute"); } } /** * Initialise the encoding of sys.stdin, sys.stdout, and - * sys.stderr, and their error handling policy, from registry variables. - * Under the console app util.jython, values reflect PYTHONIOENCODING if not overridden. - * Note that the encoding must name a Python codec, as in codecs.encode(). + * sys.stderr, and their error handling policy, from registry variables. Under the + * console app util.jython, values reflect PYTHONIOENCODING if not overridden. Note that the + * encoding must name a Python codec, as in codecs.encode(). */ private void initEncoding() { // Two registry variables, counterparts to PYTHONIOENCODING = [encoding][:errors] String encoding = registry.getProperty(PYTHON_IO_ENCODING); String errors = registry.getProperty(PYTHON_IO_ERRORS); - if (encoding==null) { + if (encoding == null) { // We still don't have an explicit selection for this: match the console. encoding = Py.getConsole().getEncoding(); } - ((PyFile)stdin).setEncoding(encoding, errors); - ((PyFile)stdout).setEncoding(encoding, errors); - ((PyFile)stderr).setEncoding(encoding, "backslashreplace"); + ((PyFile) stdin).setEncoding(encoding, errors); + ((PyFile) stdout).setEncoding(encoding, errors); + ((PyFile) stderr).setEncoding(encoding, "backslashreplace"); } @Deprecated @@ -329,6 +348,10 @@ public void setPlatform(PyObject value) { platform = value; } + public WinVersion getwindowsversion() { + return WinVersion.getWinVersion(); + } + public synchronized codecs.CodecState getCodecState() { if (codecState == null) { codecState = new codecs.CodecState(); @@ -456,7 +479,7 @@ public PyObject gettrace() { if (ts.tracefunc == null) { return Py.None; } else { - return ((PythonTraceFunction)ts.tracefunc).tracefunc; + return ((PythonTraceFunction) ts.tracefunc).tracefunc; } } @@ -474,7 +497,7 @@ public PyObject getprofile() { if (ts.profilefunc == null) { return Py.None; } else { - return ((PythonTraceFunction)ts.profilefunc).tracefunc; + return ((PythonTraceFunction) ts.profilefunc).tracefunc; } } @@ -496,14 +519,17 @@ public void setdefaultencoding(String encoding) { } public PyObject getfilesystemencoding() { - return Py.None; + return FILE_SYSTEM_ENCODING; } - /* get and setcheckinterval really do nothing, but it helps when some code tries to use these */ - public PyInteger getcheckinterval() { return new PyInteger(checkinterval); } + public PyInteger getcheckinterval() { + return new PyInteger(checkinterval); + } - public void setcheckinterval(int interval) { checkinterval = interval; } + public void setcheckinterval(int interval) { + checkinterval = interval; + } /** * Change the current working directory to the specified path. @@ -647,8 +673,8 @@ private static File getWindowsFile(String cwd, String path) { } /** - * Return the Windows drive letter from the start of the path, upper case, or 0 if - * the path does not start X: where X is a letter. + * Return the Windows drive letter from the start of the path, upper case, or 0 if the path does + * not start X: where X is a letter. * * @param path to examine * @return drive letter or char 0 if no drive letter @@ -661,13 +687,13 @@ private static char driveLetter(String path) { return Character.toUpperCase(pathDrive); } } - return (char)0; + return (char) 0; } /** * Return the Windows UNC share name from the start of the path, or null if the - * path is not of Windows UNC type. The path has to be formed with Windows-backslashes: - * slashes '/' are not accepted as a substitute here. + * path is not of Windows UNC type. The path has to be formed with Windows-backslashes: slashes + * '/' are not accepted as a substitute here. * * @param path to examine * @return share name or null @@ -717,6 +743,15 @@ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; } + /** + * Work out the root directory of the installation of Jython. Sources for this information are + * quite diverse. {@code python.home} will take precedence if set in either + * {@code postProperties} or {@code preProperties}, {@code install.root} in + * {@code preProperties}, in that order. After this, we search the class path for a JAR, or + * nagigate from the JAR deduced by from the class path, or finally {@code jarFileName}. + *

    + * We also set by side-effect: {@link #defaultPlatform} from {@code java.version}. + */ private static String findRoot(Properties preProperties, Properties postProperties, String jarFileName) { String root = null; @@ -764,6 +799,7 @@ private static String findRoot(Properties preProperties, Properties postProperti } } + /** Set {@link #defaultPlatform} by examination of the {@code java.version} JVM property. */ private static void determinePlatform(Properties props) { String version = props.getProperty("java.version"); if (version == null) { @@ -779,49 +815,154 @@ private static void determinePlatform(Properties props) { if (version.equals("12")) { version = "1.2"; } - defaultPlatform = new PyString("java" + version); + defaultPlatform = new PyShadowString("java" + version, getNativePlatform()); + } + + /** + * Emulates CPython's way to name sys.platform. Works according to this table: + * + *

    Values returned
    TypeSize
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Platform names
    SystemValue
    Linux (2.x and 3.x)linux2
    Windowswin32
    Windows/Cygwincygwin
    Mac OS Xdarwin
    OS/2os2
    OS/2 EMXos2emx
    RiscOSriscos
    AtheOSatheos
    + * + */ + public static String getNativePlatform() { + String osname = System.getProperty("os.name"); + if (osname.equals("Linux")) { + return "linux2"; + } else if (osname.equals("Mac OS X")) { + return "darwin"; + } else if (osname.toLowerCase().contains("cygwin")) { + return "cygwin"; + } else if (osname.startsWith("Windows")) { + return "win32"; + } else { + return osname.replaceAll("[\\s/]", "").toLowerCase(); + } } + /** + * Install the first argument as the application-wide {@link #registry} (a + * {@code java.util.Properties} object), merge values from system and local (or user) properties + * files, and finally allow values from {@code postProperties} to override. Usually the first + * argument is the {@code System.getProperties()}, if were allowed to access it, and therefore + * represents definitions made on the command-line. The net precedence order is: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Precedence order of registry sources
    SourceFilled by
    postPropertiesCustom {@link JythonInitializer}
    prePropertiesCommand-line definitions {@code -Dkey=value})
    ... preProperties also contains ...Environment variables via {@link org.python.util.jython}
    [user.home]/.jythonUser-specific registry file
    [python.home]/registryInstallation-wide registry file
    Environmental inferencee.g. {@code locale} command for console encoding
    + *

    + * We call {@link Options#setFromRegistry()} to translate certain final values to + * application-wide controls. By side-effect, set {@link #prefix} and {@link #exec_prefix} from + * {@link #findRoot(Properties, Properties, String)}. If it has not been set otherwise, a + * default value for python.console.encoding is derived from the OS environment, via + * {@link #getConsoleEncoding(Properties)}. + * + * @param preProperties initial registry + * @param postProperties overriding values + * @param standalone default {@code python.cachedir.skip} to true (if not otherwise defined) + * @param jarFileName as a clue to the location of the installation + */ private static void initRegistry(Properties preProperties, Properties postProperties, boolean standalone, String jarFileName) { if (registry != null) { Py.writeError("systemState", "trying to reinitialize registry"); return; } - registry = preProperties; + + // Work out sys.prefix String prefix = findRoot(preProperties, postProperties, jarFileName); + + if (prefix == null || prefix.length() == 0) { + /* + * All strategies in find_root failed (can happen in embedded use), but sys.prefix is + * generally assumed not to be null (or even None). Go for current directory. + */ + prefix = "."; + logger.config("No property 'jython.home' or other clue. sys.prefix defaulting to ''."); + } + + // sys.exec_prefix is the same initially String exec_prefix = prefix; // Load the default registry - if (prefix != null) { - if (prefix.length() == 0) { - prefix = exec_prefix = "."; - } - try { - // user registry has precedence over installed registry - File homeFile = new File(registry.getProperty("user.home"), ".jython"); - addRegistryFile(homeFile); - addRegistryFile(new File(prefix, "registry")); - } catch (Exception exc) { - // Continue - } - } - if (prefix != null) { - PySystemState.prefix = Py.newString(prefix); - } - if (exec_prefix != null) { - PySystemState.exec_prefix = Py.newString(exec_prefix); - } try { - String jythonpath = System.getenv("JYTHONPATH"); - if (jythonpath != null) { - registry.setProperty("python.path", jythonpath); - } - } catch (SecurityException e) { - // Continue + // user registry has precedence over installed registry + File homeFile = new File(registry.getProperty(USER_HOME), ".jython"); + addRegistryFile(homeFile); + addRegistryFile(new File(prefix, "registry")); + } catch (Exception exc) { + // Continue: addRegistryFile does its own logging. } + // Exposed values have to be properly-encoded objects + PySystemState.prefix = Py.fileSystemEncode(prefix); + PySystemState.exec_prefix = Py.fileSystemEncode(exec_prefix); + // Now the post properties (possibly set by custom JythonInitializer). registry.putAll(postProperties); if (standalone) { @@ -832,15 +973,12 @@ private static void initRegistry(Properties preProperties, Properties postProper } /* - * The console encoding is the one used by line-editing consoles to decode on the OS side and - * encode on the Python side. It must be a Java codec name, so any relationship to - * python.io.encoding is dubious. + * The console encoding is the one used by line-editing consoles to decode on the OS side + * and encode on the Python side. It must be a Java codec name, so any relationship to + * python.io.encoding is dubious. */ if (!registry.containsKey(PYTHON_CONSOLE_ENCODING)) { - String encoding = getPlatformEncoding(); - if (encoding != null) { - registry.put(PYTHON_CONSOLE_ENCODING, encoding); - } + registry.put(PYTHON_CONSOLE_ENCODING, getConsoleEncoding(registry)); } // Set up options from registry @@ -848,42 +986,50 @@ private static void initRegistry(Properties preProperties, Properties postProper } /** - * Return the encoding of the underlying platform, if we can work it out by any means at all. + * Try to determine the console encoding from the platform, if necessary using a sub-process to + * enquire. If everything fails, assume UTF-8. * - * @return the encoding of the underlying platform + * @param props in which to look for clues (normally the Jython registry) + * @return the console encoding (and never {@code null}) */ - private static String getPlatformEncoding() { - // first try to grab the Console encoding - String encoding = getConsoleEncoding(); - if (encoding == null) { - try { - // Not quite the console encoding (differs on Windows) - encoding = System.getProperty("file.encoding"); - } catch (SecurityException se) { - // ignore, can't do anything about it + private static String getConsoleEncoding(Properties props) { + + // From Java 8 onwards, the answer may already be to hand in the registry: + String encoding = props.getProperty("sun.stdout.encoding"); + String os = props.getProperty("os.name"); + + if (encoding != null) { + return encoding; + + } else if (os != null && os.startsWith("Windows")) { + // Go via the Windows code page built-in command "chcp". + String output = Py.getCommandResult("cmd", "/c", "chcp"); + /* + * The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or + * "활성 코드 페이지: 949". Assume the first number with 2 or more digits is the code page. + */ + final Pattern DIGITS_PATTERN = Pattern.compile("[1-9]\\d+"); + Matcher matcher = DIGITS_PATTERN.matcher(output); + if (matcher.find()) { + return "cp".concat(output.substring(matcher.start(), matcher.end())); } - } - return encoding; - } - /** - * @return the console encoding; can be null - */ - private static String getConsoleEncoding() { - String encoding = null; - try { - Method encodingMethod = java.io.Console.class.getDeclaredMethod("encoding"); - encodingMethod.setAccessible(true); // private static method - encoding = (String)encodingMethod.invoke(Console.class); - } catch (Exception e) { - // ignore any exception + } else { + // Try a Unix-like "locale charmap". + String output = Py.getCommandResult("locale", "charmap"); + // The result of "locale charmap" is just the charmap name ~ Charset or codec name. + if (output.length() > 0) { + return output; + } } - return encoding; + + // If we land here it is because we found no answer, and we will assume UTF-8. + return "utf-8"; } /** - * Merge the contents of a property file into the registry without overriding any values already - * set there. + * Merge the contents of a property file into the registry, but existing entries with the same + * key take precedence. * * @param file */ @@ -916,18 +1062,16 @@ private static void addRegistryFile(File file) { } public static Properties getBaseProperties() { - try { - return System.getProperties(); - } catch (AccessControlException ace) { - return new Properties(); - } + // Moved to PrePy since does not depend on PyObject). Retain in 2.7.x for compatibility. + return PrePy.getSystemProperties(); } public static synchronized void initialize() { initialize(null, null); } - public static synchronized void initialize(Properties preProperties, Properties postProperties) { + public static synchronized void initialize(Properties preProperties, + Properties postProperties) { initialize(preProperties, postProperties, new String[] {""}); } @@ -947,7 +1091,7 @@ public static synchronized void initialize(Properties preProperties, Properties return; } if (preProperties == null) { - preProperties = getBaseProperties(); + preProperties = PrePy.getSystemProperties(); } if (postProperties == null) { postProperties = new Properties(); @@ -955,7 +1099,8 @@ public static synchronized void initialize(Properties preProperties, Properties try { ClassLoader context = Thread.currentThread().getContextClassLoader(); if (context != null) { - if (initialize(preProperties, postProperties, argv, classLoader, adapter, context)) { + if (initialize(preProperties, postProperties, argv, classLoader, adapter, + context)) { return; } } else { @@ -1000,8 +1145,8 @@ private static boolean initialize(Properties pre, Properties post, String[] argv ClassLoader initializerClassLoader) { InputStream in = initializerClassLoader.getResourceAsStream(INITIALIZER_SERVICE); if (in == null) { - Py.writeDebug("initializer", "'" + INITIALIZER_SERVICE + "' not found on " - + initializerClassLoader); + Py.writeDebug("initializer", + "'" + INITIALIZER_SERVICE + "' not found on " + initializerClassLoader); return false; } BufferedReader r = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8"))); @@ -1009,8 +1154,8 @@ private static boolean initialize(Properties pre, Properties post, String[] argv try { className = r.readLine(); } catch (IOException e) { - Py.writeWarning("initializer", "Failed reading '" + INITIALIZER_SERVICE + "' from " - + initializerClassLoader); + Py.writeWarning("initializer", + "Failed reading '" + INITIALIZER_SERVICE + "' from " + initializerClassLoader); e.printStackTrace(System.err); return false; } @@ -1018,16 +1163,16 @@ private static boolean initialize(Properties pre, Properties post, String[] argv try { initializer = initializerClassLoader.loadClass(className); } catch (ClassNotFoundException e) { - Py.writeWarning("initializer", "Specified initializer class '" + className - + "' not found, continuing"); + Py.writeWarning("initializer", + "Specified initializer class '" + className + "' not found, continuing"); return false; } try { - ((JythonInitializer)initializer.newInstance()).initialize(pre, post, argv, - sysClassLoader, adapter); + ((JythonInitializer) initializer.getDeclaredConstructor().newInstance()).initialize(pre, + post, argv, sysClassLoader, adapter); } catch (Exception e) { - Py.writeWarning("initializer", "Failed initializing with class '" + className - + "', continuing"); + Py.writeWarning("initializer", + "Failed initializing with class '" + className + "', continuing"); e.printStackTrace(System.err); return false; } @@ -1047,7 +1192,7 @@ public static synchronized PySystemState doInitialize(Properties preProperties, initialized = true; Py.setAdapter(adapter); boolean standalone = false; - String jarFileName = Py._getJarFileName(); + String jarFileName = Py.getJarFileName(); if (jarFileName != null) { standalone = isStandalone(jarFileName); } @@ -1057,7 +1202,7 @@ public static synchronized PySystemState doInitialize(Properties preProperties, // other initializations initBuiltins(registry); -// initStaticFields(); + // initStaticFields(); // Initialize the path (and add system defaults) defaultPath = initPath(registry, standalone, jarFileName); @@ -1070,12 +1215,16 @@ public static synchronized PySystemState doInitialize(Properties preProperties, // Condition the console initConsole(registry); - // Finish up standard Python initialization... + /* + * Create the first interpreter (which is also the first instance of the sys module) and + * cache it as the default state. + */ Py.defaultSystemState = new PySystemState(); Py.setSystemState(Py.defaultSystemState); if (classLoader != null) { Py.defaultSystemState.setClassLoader(classLoader); } + Py.initClassExceptions(getDefaultBuiltins()); // Make sure that Exception classes have been loaded @@ -1097,17 +1246,15 @@ private static PyVersionInfo getVersionInfo() { s = "candidate"; } else if (Version.PY_RELEASE_LEVEL == 0x0F) { s = "final"; - } else if (Version.PY_RELEASE_LEVEL == 0xAA) { - s = "snapshot"; } else { - throw new RuntimeException("Illegal value for PY_RELEASE_LEVEL: " - + Version.PY_RELEASE_LEVEL); - } - return new PyVersionInfo( - Py.newInteger(Version.PY_MAJOR_VERSION), - Py.newInteger(Version.PY_MINOR_VERSION), - Py.newInteger(Version.PY_MICRO_VERSION), - Py.newString(s), + throw new RuntimeException( + "Illegal value for PY_RELEASE_LEVEL: " + Version.PY_RELEASE_LEVEL); + } + return new PyVersionInfo(// + Py.newInteger(Version.PY_MAJOR_VERSION), // + Py.newInteger(Version.PY_MINOR_VERSION), // + Py.newInteger(Version.PY_MICRO_VERSION), // + Py.newString(s), // Py.newInteger(Version.PY_RELEASE_SERIAL)); } @@ -1123,8 +1270,11 @@ private static void initCacheDirectory(Properties props) { } cachedir = new File(props.getProperty(PYTHON_CACHEDIR, CACHEDIR_DEFAULT_NAME)); if (!cachedir.isAbsolute()) { - cachedir = new File(prefix == null ? null : prefix.toString(), cachedir.getPath()); + String prefixString = props.getProperty("user.dir", ""); + cachedir = new File(prefixString, cachedir.getPath()); + cachedir = cachedir.getAbsoluteFile(); } + logger.log(Level.CONFIG, "cache at {0}", cachedir); } private static void initPackages(Properties props) { @@ -1142,16 +1292,17 @@ private static PyList initArgv(String[] args) { PyList argv = new PyList(); if (args != null) { for (String arg : args) { - argv.append(Py.newStringOrUnicode(arg)); + // For consistency with CPython and the standard library, sys.argv is FS-encoded. + argv.append(Py.fileSystemEncode(arg)); } } return argv; } /** - * Determine the default sys.executable value from the registry. - * If registry is not set (as in standalone jython jar), will use sys.prefix + /bin/jython(.exe) and the file may - * not exist. Users can create a wrapper in it's place to make it work in embedded environments. + * Determine the default sys.executable value from the registry. If registry is not set (as in + * standalone jython jar), we will use sys.prefix + /bin/jython(.exe) and the file may not + * exist. Users can create a wrapper in it's place to make it work in embedded environments. * Only if sys.prefix is null, returns Py.None * * @param props a Properties registry @@ -1159,26 +1310,22 @@ private static PyList initArgv(String[] args) { */ private static PyObject initExecutable(Properties props) { String executable = props.getProperty("python.executable"); - if (executable == null) { - if (prefix == null) { - return Py.None; - } else { - executable = prefix.asString() + File.pathSeparator + "bin" + File.pathSeparator; - if (Platform.IS_WINDOWS) { - executable += "jython.exe"; - } else { - executable += "jython"; - } - } + File executableFile; + if (executable != null) { + // The executable from the registry is a Unicode String path + executableFile = new File(executable); + } else { + // The prefix is a unicode or encoded bytes object + executableFile = new File(Py.fileSystemDecode(prefix), + Platform.IS_WINDOWS ? "bin\\jython.exe" : "bin/jython"); } - File executableFile = new File(executable); try { executableFile = executableFile.getCanonicalFile(); } catch (IOException ioe) { executableFile = executableFile.getAbsoluteFile(); } - return new PyString(executableFile.getPath()); + return Py.newStringOrUnicode(executableFile.getPath()); // XXX always bytes in CPython } /** @@ -1191,12 +1338,14 @@ private static PyObject initExecutable(Properties props) { * object may be accessed via {@link Py#getConsole()}. * * @param props containing (or not) python.console + * + * @see org.python.core.RegistryKey#PYTHON_CONSOLE */ private static void initConsole(Properties props) { // At this stage python.console.encoding is always defined (but null=default) String encoding = props.getProperty(PYTHON_CONSOLE_ENCODING); // The console type is chosen by this registry entry: - String consoleName = props.getProperty("python.console", "").trim(); + String consoleName = props.getProperty(PYTHON_CONSOLE, "").trim(); // And must be of type ... final Class consoleType = Console.class; @@ -1249,10 +1398,9 @@ private static void initConsole(Properties props) { /** * Convenience method wrapping {@link Py#writeWarning(String, String)} to issue a warning - * message something like: - * "console: Failed to load 'org.python.util.ReadlineConsole': msg.". It's only a warning - * because the interpreter will fall back to a plain console, but it is useful to know exactly - * why it didn't work. + * message something like: "console: Failed to load 'org.python.util.ReadlineConsole': + * msg.". It's only a warning because the interpreter will fall back to a plain console, + * but it is useful to know exactly why it didn't work. * * @param consoleName console class name we're trying to initialise * @param msg specific cause of the failure @@ -1298,7 +1446,7 @@ private static void initBuiltins(Properties props) { } // add builtins specified in the registry file - String builtinprop = props.getProperty("python.modules.builtin", ""); + String builtinprop = props.getProperty(PYTHON_MODULES_BUILTIN, ""); StringTokenizer tok = new StringTokenizer(builtinprop, ","); while (tok.hasMoreTokens()) { addBuiltin(tok.nextToken()); @@ -1319,16 +1467,13 @@ public static String getBuiltin(String name) { private static PyList initPath(Properties props, boolean standalone, String jarFileName) { PyList path = new PyList(); - addPaths(path, props.getProperty("python.path", "")); - if (prefix != null) { - String libpath = new File(prefix.toString(), "Lib").toString(); - path.append(new PyString(libpath)); - } + addPaths(path, props.getProperty(PYTHON_PATH, "")); + String libpath = new File(Py.fileSystemDecode(prefix), "Lib").toString(); + path.append(Py.fileSystemEncode(libpath)); // XXX or newUnicode? if (standalone) { // standalone jython: add the /Lib directory inside JYTHON_JAR to the path addPaths(path, jarFileName + "/Lib"); } - return path; } @@ -1365,7 +1510,8 @@ private static boolean isStandalone(String jarFileName) { private static void addPaths(PyList path, String pypath) { StringTokenizer tok = new StringTokenizer(pypath, java.io.File.pathSeparator); while (tok.hasMoreTokens()) { - path.append(new PyString(tok.nextToken().trim())); + // Use unicode object if necessary to represent the element + path.append(Py.newStringOrUnicode(tok.nextToken().trim())); // XXX or newUnicode? } } @@ -1383,16 +1529,17 @@ public static PyJavaPackage add_package(String n, String contents) { * Note. Classes found in directory and sub-directory are not made available to jython by * this call. It only makes the java package found in the directory available. This call is * mostly useful if jython is embedded in an application that deals with its own class loaders. - * A servlet container is a very good example. Calling add_classdir("/WEB-INF/classes") - * makes the java packages in WEB-INF classes available to jython import. However the actual - * classloading is completely handled by the servlet container's context classloader. + * A servlet container is a very good example. Calling + * {@code add_classdir("/WEB-INF/classes")} makes the java packages in WEB-INF classes + * available to jython import. However the actual class loading is completely handled by the + * servlet container's context classloader. */ public static void add_classdir(String directoryPath) { packageManager.addDirectory(new File(directoryPath)); } /** - * Add a .jar & .zip directory to the list of places that are searched for java .jar and .zip + * Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip * files. The .jar and .zip files found will not be cached. *

    * Note. Classes in .jar and .zip files found in the directory are not made available to @@ -1407,7 +1554,7 @@ public static void add_extdir(String directoryPath) { } /** - * Add a .jar & .zip directory to the list of places that are searched for java .jar and .zip + * Add a .jar and .zip directory to the list of places that are searched for java .jar and .zip * files. *

    * Note. Classes in .jar and .zip files found in the directory are not made available to @@ -1447,8 +1594,8 @@ static void excepthook(PyObject type, PyObject val, PyObject tb) { * Exit a Python program with the given status. * * @param status the value to exit with - * @exception Py.SystemExit always throws this exception. When caught at top level the program - * will exit. + * @throws PyException {@code SystemExit} always throws this exception. When caught at top level + * the program will exit. */ public static void exit(PyObject status) { throw new PyException(Py.SystemExit, status); @@ -1492,6 +1639,10 @@ public static PyFrame _getframe(int depth) { return f; } + public static PyDictionary _current_frames() { + return ThreadStateMapping._current_frames(); + } + public void registerCloser(Callable resourceCloser) { closer.registerCloser(resourceCloser); } @@ -1504,11 +1655,15 @@ public void cleanup() { closer.cleanup(); } - public void close() { cleanup(); } + @Override + public void close() { + cleanup(); + } public static class PySystemStateCloser { - private final Set> resourceClosers = Collections.synchronizedSet(new LinkedHashSet>()); + private final Set> resourceClosers = + Collections.synchronizedSet(new LinkedHashSet>()); private volatile boolean isCleanup = false; private final Thread shutdownHook; @@ -1524,6 +1679,7 @@ private static void cleanupOtherClosers() { Reference ref; while ((ref = systemStateQueue.poll()) != null) { PySystemStateCloser closer = sysClosers.get(ref); + sysClosers.remove(ref); closer.cleanup(); } } @@ -1562,13 +1718,14 @@ private synchronized void cleanup() { // Re-enable the management of resource closers isCleanup = false; } + private synchronized void runClosers() { // resourceClosers can be null in some strange cases if (resourceClosers != null) { /* - * Although a Set, the container iterates in the order closers were added. Make a Deque - * of it and deal from the top. - */ + * Although a Set, the container iterates in the order closers were added. Make a + * Deque of it and deal from the top. + */ LinkedList> rc = new LinkedList>(resourceClosers); Iterator> iter = rc.descendingIterator(); @@ -1586,7 +1743,8 @@ private synchronized void runClosers() { // Python scripts expect that files are closed upon an orderly cleanup of the VM. private Thread initShutdownCloser() { try { - Thread shutdownHook = new Thread(new ShutdownCloser(this), "Jython Shutdown Closer"); + Thread shutdownHook = + new Thread(new ShutdownCloser(this), "Jython Shutdown Closer"); Runtime.getRuntime().addShutdownHook(shutdownHook); return shutdownHook; } catch (SecurityException se) { @@ -1596,6 +1754,7 @@ private Thread initShutdownCloser() { } private class ShutdownCloser implements Runnable { + PySystemStateCloser closer = null; public ShutdownCloser(PySystemStateCloser closer) { @@ -1614,6 +1773,37 @@ public void run() { } + /** + * Attempt to find the OS version. The mechanism on Windows is to extract it from the result of + * {@code cmd.exe /C ver}, and otherwise (assumed Unix-like OS) to use {@code uname -v}. + */ + public static String getSystemVersionString() { + if (System.getProperty("os.name").startsWith("Windows")) { + // Windows ver command returns a string similar to: + // "Microsoft Windows [Version 10.0.10586]" + // "Microsoft Windows XP [Version 5.1.2600]" + // "Microsoft Windows [版本 10.0.17134.472]" + // We match the dots and digits within square brackets. + Pattern p = Pattern.compile("\\[.* ([\\d.]+)\\]"); + Matcher m = p.matcher(Py.getCommandResult("cmd.exe", "/c", "ver")); + return m.find() ? m.group(1) : ""; + } else { + return Py.getCommandResult("uname", "-v"); + } + } + + /** + * Run a command as a sub-process and return as the result the first line of output that + * consists of more than white space. It returns "" on any kind of error. + * + * @param command as strings (as for ProcessBuilder) + * @return the first line with content, or "" + * @deprecated Use {@link Py#getCommandResult(String...)} instead + */ + @Deprecated + private static String getCommandResult(String... command) { + return PrePy.getCommandResult(command); + } /* Traverseproc implementation */ @Override @@ -1768,17 +1958,15 @@ public int traverse(Visitproc visit, Object arg) { @Override public boolean refersDirectlyTo(PyObject ob) { - return ob != null && (ob == argv || ob == modules || ob == path - || ob == warnoptions || ob == builtins || ob == platform - || ob == meta_path || ob == path_hooks || ob == path_importer_cache - || ob == ps1 || ob == ps2 || ob == executable || ob == stdout - || ob == stderr || ob == stdin || ob == __stdout__ || ob == __stderr__ - || ob == __stdin__ || ob == __displayhook__ || ob == __excepthook__ - || ob == last_value || ob == last_type || ob == last_traceback - || ob ==__name__ || ob == __dict__); + return ob != null && (ob == argv || ob == modules || ob == path || ob == warnoptions + || ob == builtins || ob == platform || ob == meta_path || ob == path_hooks + || ob == path_importer_cache || ob == ps1 || ob == ps2 || ob == executable + || ob == stdout || ob == stderr || ob == stdin || ob == __stdout__ + || ob == __stderr__ || ob == __stdin__ || ob == __displayhook__ + || ob == __excepthook__ || ob == last_value || ob == last_type + || ob == last_traceback || ob == __name__ || ob == __dict__); } - /** * Helper abstracting common code from {@link ShutdownCloser#run()} and * {@link PySystemStateCloser#cleanup()} to close resources (such as still-open files). The @@ -1895,80 +2083,18 @@ static public FloatInfo getInfo() { ); } - - /* Traverseproc implementation */ @Override - public int traverse(Visitproc visit, Object arg) { - int retVal = super.traverse(visit, arg); - if (max != null) { - retVal = visit.visit(max, arg); - if (retVal != 0) { - return retVal; - } - } - if (max_exp != null) { - retVal = visit.visit(max_exp, arg); - if (retVal != 0) { - return retVal; - } - } - if (max_10_exp != null) { - retVal = visit.visit(max_10_exp, arg); - if (retVal != 0) { - return retVal; - } - } - if (min != null) { - retVal = visit.visit(min, arg); - if (retVal != 0) { - return retVal; - } - } - if (min_exp != null) { - retVal = visit.visit(min_exp, arg); - if (retVal != 0) { - return retVal; - } - } - if (min_10_exp != null) { - retVal = visit.visit(min_10_exp, arg); - if (retVal != 0) { - return retVal; - } - } - if (dig != null) { - retVal = visit.visit(dig, arg); - if (retVal != 0) { - return retVal; - } - } - if (mant_dig != null) { - retVal = visit.visit(mant_dig, arg); - if (retVal != 0) { - return retVal; - } - } - if (epsilon != null) { - retVal = visit.visit(epsilon, arg); - if (retVal != 0) { - return retVal; - } - } - if (radix != null) { - retVal = visit.visit(radix, arg); - if (retVal != 0) { - return retVal; - } - } - return rounds == null ? 0 : visit.visit(rounds, arg); + public PyString __repr__() { + return (PyString) Py.newString(TYPE.fastGetName() + "(" + + "max=%r, max_exp=%r, max_10_exp=%r, min=%r, min_exp=%r, min_10_exp=%r, " + + "dig=%r, mant_dig=%r, epsilon=%r, radix=%r, rounds=%r)").__mod__(this); } - @Override - public boolean refersDirectlyTo(PyObject ob) { - return ob != null && (ob == max || ob == max_exp || ob == max_10_exp || ob == min - || ob == min_exp || ob == min_10_exp || ob == dig - || ob == mant_dig || ob == epsilon || ob == radix || ob == rounds); - } + /* + * Note for Traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. + */ } @@ -1993,22 +2119,78 @@ static public LongInfo getInfo() { return new LongInfo(Py.newLong(30), Py.newLong(4)); } - - /* Traverseproc implementation */ @Override - public int traverse(Visitproc visit, Object arg) { - int retVal = super.traverse(visit, arg); - if (bits_per_digit != null) { - retVal = visit.visit(bits_per_digit, arg); - if (retVal != 0) { - return retVal; - } + public PyString __repr__() { + return (PyString) Py + .newString(TYPE.fastGetName() + "(" + "bits_per_digit=%r, sizeof_digit=%r)") + .__mod__(this); + } + + /* + * Note for Traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. + */ +} + + +@ExposedType(name = "sys.getwindowsversion", isBaseType = false) +class WinVersion extends PyTuple { + + @ExposedGet + public PyObject major, minor, build, platform, service_pack; + + public static final PyType TYPE = PyType.fromClass(WinVersion.class); + + private WinVersion(PyObject... vals) { + super(TYPE, vals); + + major = vals[0]; + minor = vals[1]; + build = vals[2]; + platform = vals[3]; + service_pack = vals[4]; + } + + public static WinVersion getWinVersion() { + try { + String sysver = PySystemState.getSystemVersionString(); + String[] sys_ver = sysver.split("\\."); + int major = Integer.parseInt(sys_ver[0]); + int minor = Integer.parseInt(sys_ver[1]); + int build = Integer.parseInt(sys_ver[2]); + if (major > 6) { + major = 6; + minor = 2; + build = 9200; + } else if (major == 6 && minor > 2) { + minor = 2; + build = 9200; + } + // emulate deprecation behavior of GetVersionEx: + return new WinVersion(Py.newInteger(major), // major + Py.newInteger(minor), // minor + Py.newInteger(build), // build + Py.newInteger(2), // platform + Py.EmptyString); // service_pack + } catch (Exception e) { + return new WinVersion(Py.EmptyString, Py.EmptyString, Py.EmptyString, Py.EmptyString, + Py.EmptyString); } - return sizeof_digit == null ? 0 : visit.visit(sizeof_digit, arg); } @Override - public boolean refersDirectlyTo(PyObject ob) { - return ob != null && (ob == bits_per_digit || ob == sizeof_digit); + public PyString __repr__() { + return (PyString) Py.newString(TYPE.fastGetName() + "(major=%r, minor=%r, build=%r, " + + "platform=%r, service_pack=%r)").__mod__(this); } + + /* + * Note for traverseproc implementation: We needn't visit the fields, because they are also + * represented as tuple elements in the parent class. So deferring to super-implementation is + * sufficient. + * + * (In CPython sys.getwindowsversion can have some keyword-only elements. So far we don't + * support these here. If that changes, an actual traverseproc implementation might be required. + */ } diff --git a/src/org/python/core/PyTableCode.java b/src/org/python/core/PyTableCode.java index e3583b9bb..6b1c8e497 100644 --- a/src/org/python/core/PyTableCode.java +++ b/src/org/python/core/PyTableCode.java @@ -5,9 +5,6 @@ * An implementation of PyCode where the actual executable content * is stored as a PyFunctionTable instance and an integer index. */ - -import org.python.modules._systemrestart; - @Untraversable public class PyTableCode extends PyBaseCode { @@ -66,31 +63,39 @@ public PyTableCode(int argcount, String varnames[], // co_lnotab, co_stacksize }; + @Override public PyObject __dir__() { PyString members[] = new PyString[__members__.length]; - for (int i = 0; i < __members__.length; i++) + for (int i = 0; i < __members__.length; i++) { members[i] = new PyString(__members__[i]); + } return new PyList(members); } private void throwReadonly(String name) { - for (int i = 0; i < __members__.length; i++) - if (__members__[i] == name) + for (int i = 0; i < __members__.length; i++) { + if (__members__[i] == name) { throw Py.TypeError("readonly attribute"); + } + } throw Py.AttributeError(name); } + @Override public void __setattr__(String name, PyObject value) { // no writable attributes throwReadonly(name); } + @Override public void __delattr__(String name) { throwReadonly(name); } private static PyTuple toPyStringTuple(String[] ar) { - if (ar == null) return Py.EmptyTuple; + if (ar == null) { + return Py.EmptyTuple; + } int sz = ar.length; PyString[] pystr = new PyString[sz]; for (int i = 0; i < sz; i++) { @@ -99,6 +104,7 @@ private static PyTuple toPyStringTuple(String[] ar) { return new PyTuple(pystr); } + @Override public PyObject __findattr_ex__(String name) { // have to craft co_varnames specially if (name == "co_varnames") { @@ -111,7 +117,7 @@ public PyObject __findattr_ex__(String name) { return toPyStringTuple(co_freevars); } if (name == "co_filename") { - return new PyString(co_filename); + return Py.fileSystemEncode(co_filename); // bytes object expected by clients } if (name == "co_name") { return new PyString(co_name); @@ -141,7 +147,7 @@ public PyObject call(ThreadState ts, PyFrame frame, PyObject closure) { } else { //System.err.println("ts: "+ts); //System.err.println("ss: "+ts.systemState); - frame.f_builtins = ts.getSystemState().builtins;; + frame.f_builtins = ts.getSystemState().builtins; } } // nested scopes: setup env with closure @@ -167,6 +173,12 @@ public PyObject call(ThreadState ts, PyFrame frame, PyObject closure) { ret = funcs.call_function(func_id, frame, ts); } catch (Throwable t) { // Convert exceptions that occurred in Java code to PyExceptions + if (!(t instanceof Exception)) { + Py.warning(Py.RuntimeWarning, "PyTableCode.call caught a Throwable that is " + + "not an Exception:\n"+t+"\nJython internals might be in a bad state now " + + "that can cause deadlocks later on." + + "\nSee http://bugs.jython.org/issue2536 for details."); + } PyException pye = Py.JavaError(t); pye.tracebackHere(frame); @@ -197,14 +209,7 @@ public PyObject call(ThreadState ts, PyFrame frame, PyObject closure) { // Restore previously defined exception ts.exception = previous_exception; - ts.frame = ts.frame.f_back; - - // Check for interruption, which is used for restarting the interpreter - // on Jython - if (ts.getSystemState()._systemRestart && Thread.currentThread().isInterrupted()) { - throw new PyException(_systemrestart.SystemRestart); - } return ret; } diff --git a/src/org/python/core/PyTupleDerived.java b/src/org/python/core/PyTupleDerived.java index 1d57425ec..34b4b3fec 100644 --- a/src/org/python/core/PyTupleDerived.java +++ b/src/org/python/core/PyTupleDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/PyType.java b/src/org/python/core/PyType.java index bbb58e2f7..26d069614 100644 --- a/src/org/python/core/PyType.java +++ b/src/org/python/core/PyType.java @@ -5,12 +5,18 @@ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicReferenceArray; +import org.python.antlr.ast.cmpopType; import org.python.expose.ExposeAsSuperclass; import org.python.expose.ExposedDelete; import org.python.expose.ExposedGet; @@ -21,22 +27,73 @@ import org.python.expose.MethodType; import org.python.expose.TypeBuilder; import org.python.modules._weakref.WeakrefModule; -import org.python.antlr.ast.cmpopType; import org.python.util.Generic; -import com.google.common.collect.MapMaker; - /** - * The Python Type object implementation. + * This class implements the Python type object and the static methods and data + * structures that support the Python type system in Jython (the type registry). + *

    + * The class PyType contains static data that describes Python types, that are + * consulted and modified through its static API (notably {@link #fromClass(Class)}). The data + * structures are guarded against modification by concurrent threads (or consultation while being + * modified). They support construction of type objects that are visible to Python. + *

    + * Bootstrapping of the type system: The first attempt to construct or get a + * PyObject (or instance of a subclass of PyObject), to use the {@link Py} + * class utilities, or to call {@link PyType#fromClass(Class)}, causes the Jython type system to be + * initialised. By the time that call returns, the type system will be in working order: any + * PyTypes the application sees will be fully valid. Also, provided that the static + * initialisation of the PyObject subclass in question is not obstructed for any other + * reason, the instance returned will also be fully functional. Note that it is possible to refer to + * C.class, and (if it is not an exposed type) to produce a PyType for it, + * without causing the static initialisation of C. + *

    + * This may be no less than the reader expected, but we mention it because, for classes encountered + * during the bootstrapping of the type system, this guarantee is not offered. The (static) + * initialisation of the type system is highly reentrant. Classes that are used by the type system + * itself, and their instances, do encounter defective PyType objects. Instances + * of these classes, which include mundane classes like PyNone and + * PyString, may exist before their class is statically initialised in the JVM sense. + * The type system has been implemented with this fact constantly in mind. The PyType + * encountered is always the "right" one — the unique instance representing the Python type of + * that class — but it may not be completely filled in. Debugging that enters these classes + * during bootstrapping will take surprising turns. Changes to these classes should also take this + * into account. + */ +/* + * As a Java object, PyType and its intimate subclass PyJavaType are not strongly encapsulated, + * internal structures are, on the whole, open to package access. A set of constructors is provided + * for different types of target class that allow us to set builtin, underlying_class and the Java + * proxy at construction time. PyType.fromClass, uses these constructors, and then calls init() to + * build the rest of the PyType state. After these steps, the PyType should be effectively + * immutable. + * + * type___new__ and PyType.newType use "blank" PyType constructors and do their own initialisation + * of the instance data. */ @ExposedType(name = "type", doc = BuiltinDocs.type_doc) public class PyType extends PyObject implements Serializable, Traverseproc { + /** + * Constants (singletons) for PyTypes that we use repeatedly in the logic of + * PyType and PyJavaType. This avoids repeated calls to + * {@link PyType#fromClass(Class)}. The inner class pattern ensures they can be constructed + * before PyType is initialised, and a unique instance of type(type) + * exists for {@link PyType#PyType(Class)} to use. + */ + protected static class Constant { + + // Identify an object to be type(type). Warning: not initialised until fromClass is called. + static final PyType PYTYPE = new PyType(false); + static final PyType PYOBJECT = fromClass(PyObject.class); + static final PyType PYSTRING = fromClass(PyString.class); + } + + /** The PyType of PyType (or type(type)). */ public static final PyType TYPE = fromClass(PyType.class); /** - * The type's name. builtin types include their fully qualified name, e.g.: - * time.struct_time. + * The type's name. builtin types include their fully qualified name, e.g.: time.struct_time. */ protected String name; @@ -44,7 +101,7 @@ public class PyType extends PyObject implements Serializable, Traverseproc { protected PyType base; /** __bases__, the base classes. */ - protected PyObject[] bases = new PyObject[0]; + protected PyObject[] bases = Registry.EMPTY_PYOBJECT_ARRAY; /** The real, internal __dict__. */ protected PyObject dict; @@ -56,12 +113,13 @@ public class PyType extends PyObject implements Serializable, Traverseproc { private long tp_flags; /** - * The Java Class instances of this type will be represented as, or null if it's - * determined by a base type. + * The Java Class that instances of this type represent (when that is a PyObject), + * or null if the type is not a PyObject, in which case the class is + * indicated through a {@link JyAttribute#JAVA_PROXY_ATTR}. */ protected Class underlying_class; - /** Whether it's a builtin type. */ + /** Whether this is a builtin type. */ protected boolean builtin; /** Whether new instances of this type can be instantiated */ @@ -90,56 +148,529 @@ public class PyType extends PyObject implements Serializable, Traverseproc { /** MethodCacheEntry version tag. */ private volatile Object versionTag = new Object(); - /** The number of __slots__ defined. */ + /** The number of __slots__ defined by this type + bases. */ private int numSlots; + /** The number of __slots__ defined by this type itself. */ + private int ownSlots = 0; + private transient ReferenceQueue subclasses_refq = new ReferenceQueue(); private Set> subclasses = Generic.linkedHashSet(); - /** Global mro cache. */ - private static final MethodCache methodCache = new MethodCache(); + /** Brevity for JyAttribute.hasAttr(obj, JyAttribute.JAVA_PROXY_ATTR). */ + static boolean hasProxyAttr(PyObject obj) { + return JyAttribute.hasAttr(obj, JyAttribute.JAVA_PROXY_ATTR); + } + + /** Brevity for JyAttribute.getAttr(obj, JyAttribute.JAVA_PROXY_ATTR). */ + static Object getProxyAttr(PyObject obj) { + return JyAttribute.getAttr(obj, JyAttribute.JAVA_PROXY_ATTR); + } + + /** Brevity for JyAttribute.setAttr(obj, JyAttribute.JAVA_PROXY_ATTR, value). */ + static void setProxyAttr(PyObject obj, Object value) { + JyAttribute.setAttr(obj, JyAttribute.JAVA_PROXY_ATTR, value); + } + + /** + * The class PyType contains a registry that describes Python types through a + * system of indexes and PyType objects. Each PyObject calls + * {@link PyType#fromClass(Class)}, which adds to this data, as it is being initialised. When + * the first descriptor is created, as the first exposed type is initialised, the registry has + * to be in a consistent, working state. + *

    + * PyType itself is a PyObject. In order to guarantee that the + * registry exists when we need it, we use a separate class whose initialisation is not hostage + * to the type system itself, as it would be it it were static data in PyType. See + * the classic + * "The + * double-checked locking problem", which we use here to be ready rather than lazy. + *

    + * A further requirement is that the registry data structures be guarded against concurrent + * access. This class also contains the methods that manipulate the state, and they synchronise + * access to it on behalf of PyType. + */ + private static final class Registry { + + /** Mapping of Java classes to their PyTypes, under construction. */ + private static final Map, PyType> classToNewType = new IdentityHashMap<>(); + + /** Mapping of Java classes to their TypeBuilders, until these are used. */ + private static final Map, TypeBuilder> classToBuilder = new HashMap<>(); + + /** Acts as a non-blocking cache for PyType look-up. */ + static ClassValue classToType = new ClassValue() { + + @Override + protected PyType computeValue(Class c) throws IncompleteType { + synchronized (Registry.class) { + // Competing threads will block and this thread will win the return. + return resolveType(c); + } + } + }; + + /** + * An exception used internally to signal a result from {@code classToType.get()} when the + * type is still under construction. + */ + private static class IncompleteType extends RuntimeException { + + /** The incompletely constructed {@code PyType}. */ + final PyType type; + + IncompleteType(PyType type) { + this.type = type; + } + } + + /** + * Mapping of Java classes to their PyTypes that have been thrown as {@link IncompleteType} + * exceptions. That action causes the {@code computeValue()} in progress to be re-tried, so + * we have to have the answer ready. + */ + private static final Map, PyType> classToThrownType = new IdentityHashMap<>(); + + /** + * A list of PyObject sub-classes, instances of which are used in the type + * system itself. We require to reference their PyTypes before Java static + * initialisation can produce a builder, because that initialisation itself depends on + * PyTypes of classes in this list, circularly. These classes must, however, be + * Java initialised and have complete PyTypes by the time the static + * initialisation of PyObject completes. + */ + // @formatter:off + private static final Class[] BOOTSTRAP_TYPES = { + PyObject.class, + PyType.class, + PyBuiltinCallable.class, + PyDataDescr.class, + PyString.class, + }; + // @formatter:on + + /** + * The set of classes that we should not, at the time we create their PyType, + * try to Java-initialise if they do not have a builder. The PyType for such a class is + * partially initialised, and needs to be completed when a builder appears. Classes come off + * this list when fully initialised, and for bootstrap types, we'll check that in the static + * initialisation of PyObject. + */ + static final Set> deferredInit = new HashSet<>(Arrays.asList(BOOTSTRAP_TYPES)); + + /** + * True if the current {@link #resolveType(Class)} call is a top-level call; false if + * {@link #resolveType(Class)} is called reentrantly, while attempting to type some other + * class. + */ + private static int depth = 0; + + /** Java types awaiting processing of their inner classes. */ + private static Set needsInners = new HashSet<>(); + + /** Handy constant: zero-length array. */ + static final PyObject[] EMPTY_PYOBJECT_ARRAY = {}; + + /** + * Test whether a given class is an exposed PyObject. Amongst other things, + * this may be used to decide that type(c) should be created as a + * PyType instead of a PyJavaType. + * + * @param c class to test + * @return whether an exposed type + */ + private static boolean isExposed(Class c) { + if (c.getAnnotation(ExposedType.class) != null) { + return true; + } else { + return ExposeAsSuperclass.class.isAssignableFrom(c); + } + } + + /** + * Return the PyType for the given target Java class. During the execution of + * this method, {@link #classToNewType} will hold any incompletely constructed + * {@link PyType}s, and a second attempt to resolve the same class will throw an + * {@link IncompleteType}, holding the incomplete {@code PyType}. This supports + * {@link PyType#fromClass(Class)} in the case where a PyType has not already + * been published. See there for caveats. If the making of a type (it will be a + * PyJavaType) might require the processing of inner classes, + * {@link PyType#fromClass(Class)} is called recursively for each. + *

    + * The caller guarantees that this thread holds the lock on the registry. + * + * @param c for which a PyType is to be created + * @throws IncompleteType to signal an incompletely constructed result + */ + static PyType resolveType(Class c) throws IncompleteType { + + // log("resolve", c); + PyType type = classToNewType.get(c); + + if (type != null) { + /* + * The type for c is still under construction, so we cannot return it normally, + * which would publish it immediately to other threads. The client must be our + * thread, calling re-entrantly, so we sneak it a reference in an exception, and + * remember we have done this. + */ + classToThrownType.put(c, type); + // log("> ", type); + throw new IncompleteType(type); + + } else if ((type = classToThrownType.remove(c)) != null) { + /* + * The type for c has been fully constructed, but was ignored because an exception + * was raised between the call to computeValue() and the return. . + */ + + } else if (depth > 0) { + /* + * This is a nested call about a class c we haven't seen before. Create (or choose + * an existing) type for c. + */ + depth += 1; + addFromClass(c); + depth -= 1; + type = classToNewType.remove(c); + } else { + /* + * This is a top-level call about a class c we haven't seen before. Create (or + * choose an existing) type for c. (In rare circumstances a thread that saw the + * cache miss will arrive here after some other thread populates classToNewType. The + * duplicate will be discarded, but the implementation must ensure this is harmless. + */ + assert needsInners.isEmpty(); + + try { + // Signal to further invocations that they are nested. + depth = 1; + + // Create (or choose an existing) type for c, accumulating classes in + // needsInners. + addFromClass(c); + + // Process inner classes too, if necessary. (This invalidates needsInners.) + if (!needsInners.isEmpty()) { + processInners(); + } + } finally { + // Guarantee subsequent calls are top-level and needsInners is empty. + depth = 0; + needsInners.clear(); + } + type = classToNewType.remove(c); + } + + /* + * Return the PyType we made for c, which is now complete. (We may still be part way + * through making others.) + */ + // log("+-->", type); + return type; + } + + /** + * Make the PyType of each inner class of the classes in {@link #needsInners} + * into an attribute of its Python representation (except where shadowed). This will + * normally mean creating a PyType for each inner class. + *

    + * Calling this method sets {@link #topLevel} = true and may replace the + * contents of {@link #needsInners}. + */ + private static void processInners() { + + // Take a copy for iteration since needsInners gets modified in the loop. + PyJavaType[] ni = needsInners.toArray(new PyJavaType[needsInners.size()]); + + // Ensure calls to fromClass are top-level. + depth = 0; + needsInners.clear(); + + for (PyJavaType javaType : ni) { + + Class forClass = javaType.getProxyType(); + + for (Class inner : forClass.getClasses()) { + /* + * Only add the class if there isn't something else with that name and it came + * from this class. + */ + if (inner.getDeclaringClass() == forClass + && javaType.dict.__finditem__(inner.getSimpleName()) == null) { + // This call is a top-level fromClass and destroys needsInners. + PyType innerType = fromClass(inner); + javaType.dict.__setitem__(inner.getSimpleName(), innerType); + } + } + } + } + + /** + * Add a new PyType or {@link PyJavaType} entry for the given class to + * {@link #classToNewType}, respecting the {@link ExposeAsSuperclass} marker interface. It + * is known at the point this method is called that the class is not already registered. + *

    + * The caller guarantees that this thread holds the lock on the registry. + * + * @param c for which a PyType is to be created in {@link #classToNewType} + */ + private static void addFromClass(Class c) { + if (ExposeAsSuperclass.class.isAssignableFrom(c)) { + // Expose c with the Python type of its superclass, recursively as necessary. + PyType exposedAs = fromClass(c.getSuperclass()); + classToNewType.put(c, exposedAs); + } else { + // Create and add a new Python type for this Java class + createType(c); + } + } + + /** + * Create a new PyType or {@link PyJavaType} for the given class in + * {@link #classToNewType}. It is known at the point this method is called that the class is + * not already registered. + *

    + * The caller guarantees that this thread holds the lock on the registry. + * + * @param c for which a PyType is to be added to {@link #classToNewType} + */ + private static void createType(Class c) { + + PyType newtype; + + if (PyObject.class.isAssignableFrom(c)) { + // c is a PyObject + if (isExposed(c)) { + // c is an exposed type (therefore should be a PyObject of some kind). + if (c != PyType.class) { + newtype = new PyType(c); + } else { + // The one PyType that PyType(Class) can't make. + newtype = Constant.PYTYPE; + } + } else { + // c is a non-exposed PyObject: expose reflectively. + newtype = new PyJavaType(c, true); + } + + } else { + // c is not a PyObject: expose reflectively via a proxy. + if (c != Class.class) { + newtype = new PyJavaType(c, false); + } else { + // The proxy that PyJavaType(Class, boolean) can't make. + newtype = PyJavaType.Constant.CLASS; + } + } + + // Enter the new PyType in the registry + classToNewType.put(c, newtype); + + /* + * This is new to the registry, and we must initialise it. Note that the if c is a + * bootstrap type init() is called, but cut short, filling only the MRO. The work will + * be completed later as a side effect of addBuilder(). Until bootstrap types are all + * fully initialised, the type system demands care in use. + */ + newtype.init(needsInners); + newtype.invalidateMethodCache(); + } + + /** + * Register the {@link TypeBuilder} for the given class. This only really makes sense for a + * PyObject. Initialising a properly-formed PyObject will usually result in a + * call to addBuilder, thanks to code inserted by the Jython type exposer. + * + * @param c class for which this is the builder + * @param builder to register + */ + static synchronized void addBuilder(Class c, TypeBuilder builder) { + /* + * If c is not registered in the type system (e.g. c is being JVM-init'd by a "use" of + * c), the next fromClass will create, register, and fully init() type(c), because we're + * giving it a builder. In that case, we'll be done. + */ + classToBuilder.put(c, builder); + PyType type = fromClass(c); + /* + * The PyTypes of bootstrap classes may be registered "half-initialised", until a + * builder is available. They end up on the deferred list. + */ + if (deferredInit.remove(c)) { + /* + * c was on the deferred list, so it was registered without a builder, and type(c) + * was "half-initialised". We need to complete the initialisation. + */ + type.init(null); + } + } + + /** + * Force static initialisation of the given sub-class of PyObject in order to + * supply a builder (via {@link #addBuilder(Class, TypeBuilder)}, if the class wants to. If + * this is a class we haven't seen before, many reentrant calls to + * {@link PyType#fromClass(Class)} are produced here, for the descriptor classes that expose + * methods and attributes. + * + * @param c target class + */ + static synchronized void staticJavaInit(Class c) throws SecurityException { + try { + // Call Class.forName to force static initialisation. + Class.forName(c.getName(), true, c.getClassLoader()); + } catch (ClassNotFoundException e) { + // Well, this is certainly surprising. + String msg = "Got ClassNotFound calling Class.forName on a class already found "; + throw new RuntimeException(msg, e); + } catch (ExceptionInInitializerError e) { + throw Py.JavaError(e); + } + } + + /** + * For each class listed as a bootstrap type, try to make sure it fully initialised a + * PyType. + * + * @return classes that did not completely initialise + */ + static synchronized Set> bootstrap() { + Set> missing = new HashSet<>(); + for (Class c : BOOTSTRAP_TYPES) { + // Look-up should force at least first-stage initialisation (if not done before). + PyType type = fromClass(c); + if (deferredInit.contains(c)) { + // Only the first stage happened: encourage the rest to happen. + staticJavaInit(c); + } + // Check various symptoms + if (type.name == null || deferredInit.contains(c)) { + missing.add(c); + } + } + return missing; + } + + // -------- Debugging for the registry -------- + private static void log(String where, Class c) { + String name = abbr(c.getName()); + System.err.printf("%s%s: %s %s thr=%s\n", pad(), where, name, names(classToNewType), + names(classToThrownType)); + // logger.log(Level.INFO, "{0}{1}: {2}", new Object[] {pad, where, name}); + } + + private static void log(String kind, PyType result) { + String r = result.toString(); + System.err.printf("%s%s %s %s thr=%s\n", pad(), kind, r, names(classToNewType), + names(classToThrownType)); + } + + /** For logging formatting. */ + private static final String PAD = " "; + + private static String abbr(String name) { + return name.replace("java.lang.", "j.l.").replace("org.python.core.", ""); + } + + private static String pad() { + int d = Math.min(Math.max(2 * depth, 0), PAD.length()); + return PAD.substring(0, d); + } + + private static List names(Map, PyType> map) { + ArrayList names = new ArrayList<>(map.size()); + for (Class k : map.keySet()) { + names.add(abbr(k.getName())); + } + return names; + } + } + + /** + * Create a "blank" PyType instance, for a Python subclass of type, + * that is, for a Python metatype. The {@link #underlying_class} is null and + * {@link #builtin} is false. This form is used by PyTypeDerived. + * + * @param subtype Python subclass of this object + */ protected PyType(PyType subtype) { super(subtype); } - private PyType() { + /** + * Create a "blank" PyType instance. The {@link #underlying_class} is + * null and it is a {@link #builtin} is false. This form is used in + * {@link #newType(PyNewWrapper, PyType, String, PyTuple, PyObject)}, which takes responsibility + * for filling in the other fields. + */ + private PyType() {} + + /** + * Create the PyType instance for type itself, or for a subclass of + * it. Depending upon the argument, the {@link #underlying_class} is either this class, or + * null, indicating a proxy. Either way, {@link #builtin} is true. In + * practice this is used to create the PyTypes for PyType itself and + * for java.lang.Class. + * + * @param isProxy if true, this is a proxy + */ + protected PyType(boolean isProxy) { + super(false); + builtin = true; + underlying_class = isProxy ? null : this.getClass(); } /** - * Creates the PyType instance for type itself. The argument just exists to make the constructor - * distinct. + * As {@link #PyType(Class)}, but also specifying the sub-type of Python type for which it is + * created. */ - private PyType(boolean ignored) { - super(ignored); + protected PyType(PyType subtype, Class c) { + super(subtype); + builtin = true; + underlying_class = c; + } + + /** + * Create a built-in type for the given Java class. This is the class to be returned by + * __tojava__(Object.class) (see {@link #__tojava__(Class)}), and by name in the + * string representation of the type. + * + * @param c the underlying class or null. + */ + protected PyType(Class c) { + // PyType.TYPE is the object type, but that may still be null so use the "advance copy". + this(Constant.PYTYPE, c); } @ExposedNew static final PyObject type___new__(PyNewWrapper new_, boolean init, PyType subtype, - PyObject[] args, String[] keywords) { + PyObject[] args, String[] keywords) { // Special case: type(x) should return x.getType() if (args.length == 1 && keywords.length == 0) { PyObject obj = args[0]; PyType objType = obj.getType(); // special case for PyStringMap so that it types as a dict - PyType psmType = PyType.fromClass(PyStringMap.class); + PyType psmType = fromClass(PyStringMap.class); if (objType == psmType) { return PyDictionary.TYPE; } return objType; } - // If that didn't trigger, we need 3 arguments. but ArgParser below may give a msg - // saying type() needs exactly 3. + /* + * If that didn't trigger, we need 3 arguments. but ArgParser below may give a msg saying + * type() needs exactly 3. + */ if (args.length + keywords.length != 3) { throw Py.TypeError("type() takes 1 or 3 arguments"); } ArgParser ap = new ArgParser("type()", args, keywords, "name", "bases", "dict"); String name = ap.getString(0); - PyTuple bases = (PyTuple)ap.getPyObjectByType(1, PyTuple.TYPE); + PyTuple bases = (PyTuple) ap.getPyObjectByType(1, PyTuple.TYPE); PyObject dict = ap.getPyObject(2); - if (!(dict instanceof PyDictionary || dict instanceof PyStringMap)) { + if (!(dict instanceof AbstractDict)) { throw Py.TypeError("type(): argument 3 must be dict, not " + dict.getType()); } return newType(new_, subtype, name, bases, dict); @@ -158,7 +689,7 @@ final void type___init__(PyObject[] args, String[] kwds) { } public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, PyTuple bases, - PyObject dict) { + PyObject dict) { PyObject[] tmpBases = bases.getArray(); PyType winner = findMostDerivedMetatype(tmpBases, metatype); @@ -166,15 +697,16 @@ public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, PyObject winnerNew = winner.lookup("__new__"); if (winnerNew != null && winnerNew != new_) { return invokeNew(winnerNew, winner, false, - new PyObject[] {new PyString(name), bases, dict}, Py.NoKeywords); + new PyObject[] {new PyString(name), bases, dict}, Py.NoKeywords); } metatype = winner; } - - // Use PyType as the metaclass for Python subclasses of Java classes rather than - // PyJavaType. Using PyJavaType as metaclass exposes the java.lang.Object methods - // on the type, which doesn't make sense for python subclasses. - if (metatype == PyType.fromClass(Class.class)) { + /* + * Use PyType as the metaclass for Python subclasses of Java classes rather than PyJavaType. + * Using PyJavaType as metaclass exposes the java.lang.Object methods on the type, which + * doesn't make sense for python subclasses. + */ + if (metatype == PyJavaType.Constant.CLASS) { metatype = TYPE; } @@ -186,12 +718,7 @@ public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, type = new PyTypeDerived(metatype); } - if (dict instanceof PyStringMap) { - dict = ((PyStringMap)dict).copy(); - } else { - dict = ((PyDictionary)dict).copy(); - } - + dict = ((AbstractDict) dict).copy(); type.name = name; type.bases = tmpBases.length == 0 ? new PyObject[] {PyObject.TYPE} : tmpBases; type.dict = dict; @@ -206,8 +733,8 @@ public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, PyType base = type.base = best_base(type.bases); if (!base.isBaseType) { - throw Py.TypeError(String.format("type '%.100s' is not an acceptable base type", - base.name)); + throw Py.TypeError( + String.format("type '%.100s' is not an acceptable base type", base.name)); } type.createAllSlots(!(base.needs_userdict || defines_dict), !base.needs_weakref); @@ -215,13 +742,68 @@ public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, type.invalidateMethodCache(); for (PyObject cur : type.bases) { - if (cur instanceof PyType) - ((PyType)cur).attachSubclass(type); + if (cur instanceof PyType) { + ((PyType) cur).attachSubclass(type); + } } return type; } + /** + * Used internally by {@link #createAllSlots()}. Builds a naive pseudo mro used to collect all + * slot names relevant for this type. + * + * @param tp type to be investigated + * @param dest list collecting all ancestors + * @param slotsMap map linking each type to its slots + * @return position of first ancestor that is not equal to or ancestor of primary base + */ + private static int findSlottedAncestors(PyType tp, List dest, + Map slotsMap) { + int baseEnd = 0; + if (tp.base != null && tp.base.numSlots > 0 && !slotsMap.containsKey(tp.base)) { + findSlottedAncestors(tp.base, dest, slotsMap); + } + baseEnd = dest.size(); + PyObject slots = tp.dict.__finditem__("__slots__"); + if (slots != null) { + dest.add(tp); // to keep track of order + slotsMap.put(tp, slots); + } + if (tp.bases.length > 1) { + for (PyObject base : tp.bases) { + if (base == tp.base || !(base instanceof PyType) || ((PyType) base).numSlots == 0 + || slotsMap.containsKey((PyType) base)) { + continue; + } + findSlottedAncestors((PyType) base, dest, slotsMap); + } + } + return baseEnd; + } + + /** + * Used internally by {@link #createAllSlots()}. Adds all names in {@code slots} to + * {@code dest}. + * + * @param slots names to be added as slots + * @param dest set collecting all slots + */ + private static void insertSlots(PyObject slots, Set dest) { + if (slots instanceof PyString) { + slots = new PyTuple(slots); + } + // Check for valid slot names and create them. + for (PyObject slot : slots.asIterable()) { + String slotName = confirmIdentifier(slot); + if (slotName.equals("__dict__") || slotName.equals("__weakref__")) { + continue; + } + dest.add(slotName); + } + } + /** * Create all slots and related descriptors. * @@ -229,29 +811,60 @@ public static PyObject newType(PyNewWrapper new_, PyType metatype, String name, * @param mayAddWeak whether a __weakref__ descriptor is allowed on this type */ private void createAllSlots(boolean mayAddDict, boolean mayAddWeak) { - numSlots = base.numSlots; + List slottedAncestors = Generic.list(base.mro.length + (bases.length - 1) * 3 + 1); + Map slotsMap = Generic.identityHashMap(slottedAncestors.size()); + /* + * Here we would need the mro to search for slots (also in secondary bases) properly, but + * mro hasn't been set up yet. So we quickly (?) build a pseudo mro sufficient to find all + * slots. + */ + int baseEnd = findSlottedAncestors(this, slottedAncestors, slotsMap); + // baseEnd is the first position of an ancestor not equal to or ancestor of primary base + int slots_tmp = 0; // used for various purpose, first to accumulate maximal slot count + for (PyType anc : slottedAncestors) { + slots_tmp += anc.numSlots; + } + /* + * In allSlots we collect slots of primary base first, then of this type, then of secondary + * bases. At any time we prevent it from containing __dict__ or __weakref__. we know the + * required capacity, so the set likely won't be resized. + */ + Set allSlots = Generic.linkedHashSet(2 * slots_tmp); + if (baseEnd > 0) { + for (int i = 0; i < baseEnd; ++i) { + insertSlots(slotsMap.get(slottedAncestors.get(i)), allSlots); + } + } + assert allSlots.size() == base.numSlots; + boolean wantDict = false; boolean wantWeak = false; PyObject slots = dict.__finditem__("__slots__"); - + ownSlots = 0; // to keep track of slots defined by this type itself for isSolidBase + /* + * from now on, slots_tmp stores position where other ancestors than primary base begin + * (points to this type if it defines own slots) + */ if (slots == null) { wantDict = mayAddDict; wantWeak = mayAddWeak; + slots_tmp = baseEnd; } else { if (slots instanceof PyString) { slots = new PyTuple(slots); } - // Check for valid slot names and create them. Handle two special cases for (PyObject slot : slots.asIterable()) { String slotName = confirmIdentifier(slot); if (slotName.equals("__dict__")) { if (!mayAddDict || wantDict) { - // CPython is stricter here, but this seems arbitrary. To reproduce CPython - // behavior + /* + * CPython is stricter here, but this seems arbitrary. To reproduce CPython + * behavior: + */ // if (base != PyObject.TYPE) { - // throw Py.TypeError("__dict__ slot disallowed: we already got one"); + // throw Py.TypeError("__dict__ slot disallowed: we already got one"); // } } else { wantDict = true; @@ -259,26 +872,24 @@ private void createAllSlots(boolean mayAddDict, boolean mayAddWeak) { } } else if (slotName.equals("__weakref__")) { if ((!mayAddWeak || wantWeak) && base != PyObject.TYPE) { - // CPython is stricter here, but this seems arbitrary. To reproduce CPython - // behavior + /* + * CPython is stricter here, but this seems arbitrary. To reproduce CPython + * behavior: + */ // if (base != PyObject.TYPE) { - // throw Py.TypeError("__weakref__ slot disallowed: we already got one"); + // throw Py.TypeError("__weakref__ slot disallowed: we already got one"); // } } else { wantWeak = true; continue; } } - - slotName = mangleName(name, slotName); - if (dict.__finditem__(slotName) == null) { - dict.__setitem__(slotName, new PySlot(this, slotName, numSlots++)); + if (allSlots.add(slotName)) { + ++ownSlots; } } - - // Secondary bases may provide weakrefs or dict - if (bases.length > 1 - && ((mayAddDict && !wantDict) || (mayAddWeak && !wantWeak))) { + if (bases.length > 1 && ((mayAddDict && !wantDict) || (mayAddWeak && !wantWeak))) { + // Secondary bases may provide weakrefs or dict for (PyObject base : bases) { if (base == this.base) { // Skip primary base @@ -296,7 +907,7 @@ private void createAllSlots(boolean mayAddDict, boolean mayAddWeak) { break; } - PyType baseType = (PyType)base; + PyType baseType = (PyType) base; if (mayAddDict && !wantDict && baseType.needs_userdict) { wantDict = true; } @@ -309,7 +920,28 @@ private void createAllSlots(boolean mayAddDict, boolean mayAddWeak) { } } } + slots_tmp = baseEnd + 1; + } + for (int i = slots_tmp; i < slottedAncestors.size(); ++i) { + insertSlots(slotsMap.get(slottedAncestors.get(i)), allSlots); + } + numSlots = allSlots.size(); + int slotPos = 0; + Iterator slotIter = allSlots.iterator(); + // skip slot names belonging to primary base (i.e. first base.numSlots ones) + for (; slotPos < base.numSlots; ++slotPos) { + slotIter.next(); + } + while (slotIter.hasNext()) { + String slotName = slotIter.next(); + slotName = mangleName(name, slotName); + if (dict.__finditem__(slotName) == null) { + dict.__setitem__(slotName, new PySlot(this, slotName, slotPos++)); + } else { + --numSlots; + } } + assert slotPos == numSlots; if (wantDict) { createDictSlot(); @@ -326,36 +958,37 @@ private void createAllSlots(boolean mayAddDict, boolean mayAddWeak) { private void createDictSlot() { String doc = "dictionary for instance variables (if defined)"; dict.__setitem__("__dict__", new PyDataDescr(this, "__dict__", PyObject.class, doc) { - @Override - public boolean implementsDescrGet() { - return true; - } - @Override - public Object invokeGet(PyObject obj) { - return obj.getDict(); - } + @Override + public boolean implementsDescrGet() { + return true; + } - @Override - public boolean implementsDescrSet() { - return true; - } + @Override + public Object invokeGet(PyObject obj) { + return obj.getDict(); + } - @Override - public void invokeSet(PyObject obj, Object value) { - obj.setDict((PyObject)value); - } + @Override + public boolean implementsDescrSet() { + return true; + } - @Override - public boolean implementsDescrDelete() { - return true; - } + @Override + public void invokeSet(PyObject obj, Object value) { + obj.setDict((PyObject) value); + } - @Override - public void invokeDelete(PyObject obj) { - obj.delDict(); - } - }); + @Override + public boolean implementsDescrDelete() { + return true; + } + + @Override + public void invokeDelete(PyObject obj) { + obj.delDict(); + } + }); needs_userdict = true; } @@ -365,23 +998,23 @@ public void invokeDelete(PyObject obj) { private void createWeakrefSlot() { String doc = "list of weak references to the object (if defined)"; dict.__setitem__("__weakref__", new PyDataDescr(this, "__weakref__", PyObject.class, doc) { - private static final String writeMsg = - "attribute '%s' of '%s' objects is not writable"; - private void notWritable(PyObject obj) { - throw Py.AttributeError(String.format(writeMsg, "__weakref__", - obj.getType().fastGetName())); - } + private static final String writeMsg = "attribute '%s' of '%s' objects is not writable"; - @Override - public boolean implementsDescrGet() { - return true; - } + private void notWritable(PyObject obj) { + throw Py.AttributeError( + String.format(writeMsg, "__weakref__", obj.getType().fastGetName())); + } - @Override - public Object invokeGet(PyObject obj) { - PyList weakrefs = WeakrefModule.getweakrefs(obj); - switch (weakrefs.size()) { + @Override + public boolean implementsDescrGet() { + return true; + } + + @Override + public Object invokeGet(PyObject obj) { + PyList weakrefs = WeakrefModule.getweakrefs(obj); + switch (weakrefs.size()) { case 0: return Py.None; case 1: @@ -389,30 +1022,30 @@ public Object invokeGet(PyObject obj) { default: return weakrefs; - } } + } - @Override - public boolean implementsDescrSet() { - return true; - } + @Override + public boolean implementsDescrSet() { + return true; + } - @Override - public void invokeSet(PyObject obj, Object value) { - // XXX: Maybe have PyDataDescr do notWritable() for us - notWritable(obj); - } + @Override + public void invokeSet(PyObject obj, Object value) { + // XXX: Maybe have PyDataDescr do notWritable() for us + notWritable(obj); + } - @Override - public boolean implementsDescrDelete() { - return true; - } + @Override + public boolean implementsDescrDelete() { + return true; + } - @Override - public void invokeDelete(PyObject obj) { - notWritable(obj); - } - }); + @Override + public void invokeDelete(PyObject obj) { + notWritable(obj); + } + }); needs_weakref = true; } @@ -461,8 +1094,7 @@ public static void ensureDoc(PyObject dict) { } /** - * Ensure dict contains a __module__, retrieving it from the current frame if it - * doesn't exist. + * Ensure dict contains a __module__, retrieving it from the current frame if it doesn't exist. * * @param dict a PyObject mapping */ @@ -481,10 +1113,10 @@ public static void ensureModule(PyObject dict) { } private static PyObject invokeNew(PyObject new_, PyType type, boolean init, PyObject[] args, - String[] keywords) { + String[] keywords) { PyObject obj; if (new_ instanceof PyNewWrapper) { - obj = ((PyNewWrapper)new_).new_impl(init, type, args, keywords); + obj = ((PyNewWrapper) new_).new_impl(init, type, args, keywords); } else { int n = args.length; PyObject[] typePrepended = new PyObject[n + 1]; @@ -496,52 +1128,76 @@ private static PyObject invokeNew(PyObject new_, PyType type, boolean init, PyOb } /** - * Called on builtin types for a particular class. Should fill in dict, name, mro, base and - * bases from the class. + * Complete the initialisation of the PyType for an exposed PyObject. + * If the type is one of the deferred types (types used in bootstrapping the type system, + * predominantly), this will only fill in {@link #mro}, {@link #base} and {@link #bases}, and + * only provisionally. In that case, a second call is made as soon as + * {@link #addBuilder(Class, TypeBuilder)} is called by the initialisation of the type. In most + * cases, and on the second visit for deferred types, this call will fill {@link #dict}, + * {@link #name} and all other descriptive state using the exposed characteristics. + *

    + * The caller guarantees that this thread holds the lock on the registry. + * + * @param needsInners ignored in the base implementation (see {@link PyJavaType#init(Set)} */ - protected void init(Class forClass, Set needsInners) { - underlying_class = forClass; - if (underlying_class == PyObject.class) { - mro = new PyType[] {this}; - } else { - Class baseClass; - if (!BootstrapTypesSingleton.getInstance().contains(underlying_class)) { - baseClass = getClassToBuilder().get(underlying_class).getBase(); - } else { - baseClass = PyObject.class; + protected void init(Set needsInners) { + + Class forClass = underlying_class; + + /* + * We will have a builder already if the class has Java-initialised. We remove builder from + * list as we don't need it anymore, and it holds a reference to the class c. + */ + TypeBuilder builder = Registry.classToBuilder.remove(forClass); + if (builder == null) { + // Consider forcing static initialisation in order to get a builder. + if (!Registry.deferredInit.contains(forClass)) { + Registry.staticJavaInit(forClass); + builder = Registry.classToBuilder.remove(forClass); } + } + + if (builder == null) { + /* + * No builder has been supplied yet. Be content with partial initialisation of the + * PyType. When we have a builder, we'll init this again. + */ + Registry.deferredInit.add(forClass); + computeLinearMro(PyObject.class); + + } else { + /* We have a builder so we can go the whole way. Signal c is no longer deferred. */ + Registry.deferredInit.remove(forClass); + Class baseClass = builder.getBase(); if (baseClass == Object.class) { + // Base was not explicitly declared: default is Java super-class. baseClass = underlying_class.getSuperclass(); } computeLinearMro(baseClass); - } - if (BootstrapTypesSingleton.getInstance().contains(underlying_class)) { - // init will be called again from addBuilder which also removes underlying_class from - // BOOTSTRAP_TYPES - return; - } - TypeBuilder builder = getClassToBuilder().get(underlying_class); - name = builder.getName(); - dict = builder.getDict(this); - String doc = builder.getDoc(); - // XXX: Can't create a __doc__ str until the PyBaseString/PyString types are - // created - if (dict.__finditem__("__doc__") == null && forClass != PyBaseString.class - && forClass != PyString.class) { - PyObject docObj; - if (doc != null) { - docObj = new PyString(doc); - } else { - // XXX: Hack: Py.None may be null during bootstrapping. Most types - // encountered then should have docstrings anyway - docObj = Py.None == null ? new PyString() : Py.None; + + // The builder supplies the name and collection of exposed methods and properties + name = builder.getName(); + dict = builder.getDict(this); + String doc = builder.getDoc(); + + // Create a doc string if we don't have one already. + if (dict.__finditem__("__doc__") == null) { + PyObject docObj; + if (doc != null) { + // Not PyString(doc) as PyString.TYPE may be null during bootstrapping. + docObj = new PyString(Constant.PYSTRING, doc); + } else { + // Not Py.None to avoid load & init of Py module and all its constants. + docObj = PyNone.getInstance(); + } + dict.__setitem__("__doc__", docObj); } - dict.__setitem__("__doc__", docObj); + + setIsBaseType(builder.getIsBaseType()); + needs_userdict = dict.__finditem__("__dict__") != null; + instantiable = dict.__finditem__("__new__") != null; + cacheDescrBinds(); } - setIsBaseType(builder.getIsBaseType()); - needs_userdict = dict.__finditem__("__dict__") != null; - instantiable = dict.__finditem__("__new__") != null; - cacheDescrBinds(); } /** @@ -549,14 +1205,19 @@ protected void init(Class forClass, Set needsInners) { * followed by the mro of baseClass. */ protected void computeLinearMro(Class baseClass) { - base = PyType.fromClass(baseClass, false); - mro = new PyType[base.mro.length + 1]; - System.arraycopy(base.mro, 0, mro, 1, base.mro.length); + if (underlying_class == PyObject.class) { + // Special case PyObject: there is no ancestor base: MRO is just {this}. + mro = new PyType[1]; + } else { + // MRO of base, with this PyType at the front. + base = fromClass(baseClass); + mro = new PyType[base.mro.length + 1]; + System.arraycopy(base.mro, 0, mro, 1, base.mro.length); + bases = new PyObject[] {base}; + } mro[0] = this; - bases = new PyObject[] {base}; } - /** * Determine if this type is a descriptor, and if so what kind. */ @@ -581,11 +1242,10 @@ public PyObject getStatic() { */ public final boolean needsFinalizer() { /* - * It might be sluggish to assume that if a finalizer was needed - * once, this would never change. However since an expensive - * FinalizeTrigger was created anyway, it won't hurt to keep it. - * Whether there actually is a __del__ in the dict, will be checked - * again when the finalizer runs. + * It might be sluggish to assume that if a finalizer was needed once, this would never + * change. However since an expensive FinalizeTrigger was created anyway, it won't hurt to + * keep it. Whether there actually is a __del__ in the dict, will be checked again when the + * finalizer runs. */ if (needs_finalizer) { return true; @@ -601,9 +1261,9 @@ public final boolean needsFinalizer() { */ public void compatibleForAssignment(PyType other, String attribute) { if (!getLayout().equals(other.getLayout()) || needs_userdict != other.needs_userdict - || needs_finalizer != other.needs_finalizer) { + || needs_finalizer != other.needs_finalizer) { throw Py.TypeError(String.format("%s assignment: '%s' object layout differs from '%s'", - attribute, other.fastGetName(), fastGetName())); + attribute, other.fastGetName(), fastGetName())); } } @@ -621,8 +1281,7 @@ private PyType getLayout() { } /** - * Get the most parent Java proxy Class from bases, tallying any encountered Java - * interfaces. + * Get the most parent Java proxy Class from bases, tallying any encountered Java interfaces. * * @param bases array of base Jython classes * @param interfaces List for collecting interfaces to @@ -636,7 +1295,7 @@ private static Class getJavaLayout(PyObject[] bases, List> interface if (!(base instanceof PyType)) { continue; } - Class proxy = ((PyType)base).getProxyType(); + Class proxy = ((PyType) base).getProxyType(); if (proxy == null) { continue; } @@ -671,11 +1330,11 @@ private void setupProxy(Class baseProxyClass, List> interfaces) { if (module != null) { proxyName = module.toString() + "$" + proxyName; } - Class proxyClass = MakeProxies.makeProxy(baseProxyClass, interfaces, name, proxyName, - dict); - JyAttribute.setAttr(this, JyAttribute.JAVA_PROXY_ATTR, proxyClass); + Class proxyClass = + MakeProxies.makeProxy(baseProxyClass, interfaces, name, proxyName, dict); + setProxyAttr(this, proxyClass); - PyType proxyType = PyType.fromClass(proxyClass, false); + PyType proxyType = fromClass(proxyClass); List cleanedBases = Generic.list(); boolean addedProxyType = false; for (PyObject base : bases) { @@ -683,19 +1342,23 @@ private void setupProxy(Class baseProxyClass, List> interfaces) { cleanedBases.add(base); continue; } - Class proxy = ((PyType)base).getProxyType(); + Class proxy = ((PyType) base).getProxyType(); if (proxy == null) { // non-proxy types go straight into our lookup cleanedBases.add(base); } else { if (!(base instanceof PyJavaType)) { - // python subclasses of proxy types need to be added as a base so their - // version of methods will show up + /* + * python subclasses of proxy types need to be added as a base so their version + * of methods will show up. + */ cleanedBases.add(base); } else if (!addedProxyType) { - // Only add a single Java type, since everything's going to go through the - // proxy type + /* + * Only add a single Java type, since everything's going to go through the proxy + * type. + */ cleanedBases.add(proxyType); addedProxyType = true; } @@ -710,12 +1373,14 @@ protected PyObject richCompare(PyObject other, cmpopType op) { return null; } - // If there is a __cmp__ method defined, let it be called instead - // of our dumb function designed merely to warn. See CPython bug #7491. - if (__findattr__("__cmp__") != null || ((PyType)other).__findattr__("__cmp__") != null) { + /* + * If there is a __cmp__ method defined, let it be called instead of our dumb function + * designed merely to warn. See CPython bug #7491. + */ + if (__findattr__("__cmp__") != null || ((PyType) other).__findattr__("__cmp__") != null) { return null; } - + // Py3K warning if comparison isn't == or != if (Options.py3k_warning && op != cmpopType.Eq && op != cmpopType.NotEq) { Py.warnPy3k("type inequality comparisons not supported in 3.x"); @@ -726,16 +1391,23 @@ protected PyObject richCompare(PyObject other, cmpopType op) { int hash1 = object___hash__(); int hash2 = other.object___hash__(); switch (op) { - case Lt: return hash1 < hash2 ? Py.True : Py.False; - case LtE: return hash1 <= hash2 ? Py.True : Py.False; - case Eq: return hash1 == hash2 ? Py.True : Py.False; - case NotEq: return hash1 != hash2 ? Py.True : Py.False; - case Gt: return hash1 > hash2 ? Py.True : Py.False; - case GtE: return hash1 >= hash2 ? Py.True : Py.False; - default: return null; + case Lt: + return hash1 < hash2 ? Py.True : Py.False; + case LtE: + return hash1 <= hash2 ? Py.True : Py.False; + case Eq: + return hash1 == hash2 ? Py.True : Py.False; + case NotEq: + return hash1 != hash2 ? Py.True : Py.False; + case Gt: + return hash1 > hash2 ? Py.True : Py.False; + case GtE: + return hash1 >= hash2 ? Py.True : Py.False; + default: + return null; } } - + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.type___eq___doc) public PyObject type___eq__(PyObject other) { return richCompare(other, cmpopType.Eq); @@ -765,11 +1437,12 @@ public PyObject type___ge__(PyObject other) { public PyObject type___gt__(PyObject other) { return richCompare(other, cmpopType.Gt); } - + @ExposedGet(name = "__base__") public PyObject getBase() { - if (base == null) + if (base == null) { return Py.None; + } return base; } @@ -788,19 +1461,19 @@ public void setBases(PyObject newBasesTuple) { if (!(newBasesTuple instanceof PyTuple)) { throw Py.TypeError("bases must be a tuple"); } - PyObject[] newBases = ((PyTuple)newBasesTuple).getArray(); + PyObject[] newBases = ((PyTuple) newBasesTuple).getArray(); if (newBases.length == 0) { - throw Py.TypeError("can only assign non-empty tuple to __bases__, not " - + newBasesTuple); + throw Py.TypeError( + "can only assign non-empty tuple to __bases__, not " + newBasesTuple); } for (int i = 0; i < newBases.length; i++) { if (!(newBases[i] instanceof PyType)) { if (!(newBases[i] instanceof PyClass)) { throw Py.TypeError(name + ".__bases__ must be a tuple of old- or new-style " - + "classes, not " + newBases[i]); + + "classes, not " + newBases[i]); } } else { - if (((PyType)newBases[i]).isSubType(this)) { + if (((PyType) newBases[i]).isSubType(this)) { throw Py.TypeError("a __bases__ item causes an inheritance cycle"); } } @@ -818,18 +1491,18 @@ public void setBases(PyObject newBasesTuple) { mro_subclasses(savedSubMros); for (PyObject saved : savedBases) { if (saved instanceof PyType) { - ((PyType)saved).detachSubclass(this); + ((PyType) saved).detachSubclass(this); } } for (PyObject newb : newBases) { if (newb instanceof PyType) { - ((PyType)newb).attachSubclass(this); + ((PyType) newb).attachSubclass(this); } } } catch (PyException t) { for (Iterator it = savedSubMros.iterator(); it.hasNext();) { - PyType subtype = (PyType)it.next(); - PyObject[] subtypeSavedMro = (PyObject[])it.next(); + PyType subtype = (PyType) it.next(); + PyObject[] subtypeSavedMro = (PyObject[]) it.next(); subtype.mro = subtypeSavedMro; } bases = savedBases; @@ -849,29 +1522,39 @@ boolean isAbstract() { return (tp_flags & Py.TPFLAGS_IS_ABSTRACT) != 0; } + /** + * Set the {@link #mro} field from the Python {@code mro()} method which uses + * ({@link #computeMro()} by default. We must repeat this whenever the bases of this type + * change, which they may in general for classes defined in Python. + */ private void mro_internal() { + if (getType() == TYPE) { - mro = computeMro(); + mro = computeMro(); // Shortcut + } else { + // Use the mro() method, which may have been redefined to find the MRO as an array. PyObject mroDescr = getType().lookup("mro"); if (mroDescr == null) { throw Py.AttributeError("mro"); } PyObject[] result = Py.make_array(mroDescr.__get__(null, getType()).__call__(this)); + // Verify that Python types in the MRO have a "solid base" in common with this type. PyType solid = solid_base(this); + for (PyObject cls : result) { if (cls instanceof PyClass) { continue; - } - if (!(cls instanceof PyType)) { - throw Py.TypeError(String.format("mro() returned a non-class ('%.500s')", - cls.getType().fastGetName())); - } - PyType t = (PyType)cls; - if (!solid.isSubType(solid_base(t))) { - throw Py.TypeError(String.format("mro() returned base with unsuitable layout " - + "('%.500s')", t.fastGetName())); + } else if (cls instanceof PyType) { + PyType t = (PyType) cls; + if (!solid.isSubType(solid_base(t))) { + String fmt = "mro() returned base with unsuitable layout ('%.500s')"; + throw Py.TypeError(String.format(fmt, t.fastGetName())); + } + } else { + String fmt = "mro() returned a non-class ('%.500s')"; + throw Py.TypeError(String.format(fmt, cls.getType().fastGetName())); } } mro = result; @@ -926,18 +1609,41 @@ public synchronized final PyObject type___subclasses__() { cleanup_subclasses(); for (WeakReference ref : subclasses) { PyType subtype = ref.get(); - if (subtype == null) + if (subtype == null) { continue; + } result.append(subtype); } return result; } + @ExposedMethod(doc = BuiltinDocs.type___subclasscheck___doc) + public synchronized final boolean type___subclasscheck__(PyObject inst) { + /* + * We cannot directly call Py.isSubClass(inst, this), because that would yield endless + * recursion under some circumstances (e.g. in test_collections). + */ + return Py.recursiveIsSubClass(inst, this); + } + + @ExposedMethod(doc = BuiltinDocs.type___instancecheck___doc) + public synchronized final boolean type___instancecheck__(PyObject inst) { + /* + * We cannot directly call Py.isInstance(inst, this), because that would yield endless + * recursion. So we inline the essential parts from there, excluding checker-delegation and + * PyTuple special case. + */ + if (inst.getType() == this) { + return true; + } + return Py.recursiveIsInstance(inst, this); + } + /** * Returns the Java Class that this type inherits from, or null if this type is Python-only. */ public Class getProxyType() { - return (Class) JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR); + return (Class) getProxyAttr(this); } private synchronized void attachSubclass(PyType subtype) { @@ -978,7 +1684,7 @@ private static void fill_classic_mro(List acc, PyClass classic_cl) { } PyObject[] bases = classic_cl.__bases__.getArray(); for (PyObject base : bases) { - fill_classic_mro(acc,(PyClass)base); + fill_classic_mro(acc, (PyClass) base); } } @@ -989,46 +1695,67 @@ private static PyObject[] classic_mro(PyClass classic_cl) { } @ExposedMethod(defaults = "null", doc = BuiltinDocs.type_mro_doc) - final PyList type_mro(PyObject o) { - if (o == null) { - return new PyList(computeMro()); - } - return new PyList(((PyType)o).computeMro()); + final PyList type_mro(PyObject X) { + // This is either X.mro (where X is a type object) or type.mro(X) + PyObject[] res = (X == null) ? computeMro() : ((PyType) X).computeMro(); + return new PyList(res); } + /** + * Examine the bases (which must contain no repetition) and the MROs of these bases and return + * the MRO of this class. + * + * @return the MRO of this class + */ PyObject[] computeMro() { + // First check that there are no duplicates amongst the bases of this class. for (int i = 0; i < bases.length; i++) { PyObject cur = bases[i]; for (int j = i + 1; j < bases.length; j++) { if (bases[j] == cur) { PyObject name = cur.__findattr__("__name__"); - throw Py.TypeError("duplicate base class " + - (name == null ? "?" : name.toString())); + throw Py.TypeError( + "duplicate base class " + (name == null ? "?" : name.toString())); } } } + // Build a table of the MROs of the bases as MROMergeState objects. MROMergeState[] toMerge = new MROMergeState[bases.length + 1]; for (int i = 0; i < bases.length; i++) { toMerge[i] = new MROMergeState(); if (bases[i] instanceof PyType) { - toMerge[i].mro = ((PyType)bases[i]).mro; + toMerge[i].mro = ((PyType) bases[i]).mro; } else if (bases[i] instanceof PyClass) { - toMerge[i].mro = classic_mro((PyClass)bases[i]); + toMerge[i].mro = classic_mro((PyClass) bases[i]); } } + + // Append to this table the list of bases of this class toMerge[bases.length] = new MROMergeState(); toMerge[bases.length].mro = bases; + // The head of the output MRO is the current class itself. List mro = Generic.list(); mro.add(this); + + // Now execute the core of the MRO generation algorithm. return computeMro(toMerge, mro); } + /** + * Core algorithm for computing the MRO for "new-style" (although it's been a while) Python + * classes. + * + * @param toMerge data structure representing the (partly processed) MROs of bases. + * @param mro partial MRO (initially only this class) + * @return the MRO of this class + */ PyObject[] computeMro(MROMergeState[] toMerge, List mro) { boolean addedProxy = false; - PyType proxyAsType = !JyAttribute.hasAttr(this, JyAttribute.JAVA_PROXY_ATTR) ? - null : PyType.fromClass(((Class)JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)), false); + Class thisProxyAttr = this.getProxyType(); + PyType proxyAsType = thisProxyAttr == null ? null : fromClass(thisProxyAttr); + scan : for (int i = 0; i < toMerge.length; i++) { if (toMerge[i].isMerged()) { continue scan; @@ -1040,20 +1767,23 @@ PyObject[] computeMro(MROMergeState[] toMerge, List mro) { continue scan; } } - if (!addedProxy && !(this instanceof PyJavaType) && candidate instanceof PyJavaType - && JyAttribute.hasAttr(candidate, JyAttribute.JAVA_PROXY_ATTR) - && PyProxy.class.isAssignableFrom( - ((Class)JyAttribute.getAttr(candidate, JyAttribute.JAVA_PROXY_ATTR))) - && JyAttribute.getAttr(candidate, JyAttribute.JAVA_PROXY_ATTR) != - JyAttribute.getAttr(this, JyAttribute.JAVA_PROXY_ATTR)) { - // If this is a subclass of a Python class that subclasses a Java class, slip the - // proxy for this class in before the proxy class in the superclass' mro. - // This exposes the methods from the proxy generated for this class in addition to - // those generated for the superclass while allowing methods from the superclass to - // remain visible from the proxies. - mro.add(proxyAsType); - addedProxy = true; + + if (!addedProxy && !(this instanceof PyJavaType) && candidate instanceof PyJavaType) { + Class candidateProxyAttr = ((PyJavaType) candidate).getProxyType(); + if (candidateProxyAttr != null && PyProxy.class.isAssignableFrom(candidateProxyAttr) + && candidateProxyAttr != thisProxyAttr) { + /* + * If this is a subclass of a Python class that subclasses a Java class, slip + * the proxy for this class in before the proxy class in the superclass' mro. + * This exposes the methods from the proxy generated for this class in addition + * to those generated for the superclass while allowing methods from the + * superclass to remain visible from the proxies. + */ + mro.add(proxyAsType); + addedProxy = true; + } } + mro.add(candidate); // Was that our own proxy? addedProxy |= candidate == proxyAsType; @@ -1062,24 +1792,31 @@ PyObject[] computeMro(MROMergeState[] toMerge, List mro) { } i = -1; // restart scan } + for (MROMergeState mergee : toMerge) { if (!mergee.isMerged()) { handleMroError(toMerge, mro); } } + return mro.toArray(new PyObject[mro.size()]); } /** - * Must either throw an exception, or bring the merges in toMerge to completion by - * finishing filling in mro. + * This method is called when the {@link #computeMro(MROMergeState[], List)} reaches an impasse + * as far as its official algorithm is concerned, with the partial MRO and current state of the + * working lists at the point the problem is detected. The base implementation raises a Python + * {@code TypeError}, diagnosing the problem. + * + * @param toMerge partially processed algorithm state + * @param mro output MRO (incomplete) */ void handleMroError(MROMergeState[] toMerge, List mro) { - StringBuilder msg = new StringBuilder("Cannot create a consistent method resolution\n" - + "order (MRO) for bases "); + StringBuilder msg = new StringBuilder( + "Cannot create a consistent method resolution\norder (MRO) for bases "); Set set = Generic.set(); for (MROMergeState mergee : toMerge) { - if(!mergee.isMerged()) { + if (!mergee.isMerged()) { set.add(mergee.mro[0]); } } @@ -1091,14 +1828,16 @@ void handleMroError(MROMergeState[] toMerge, List mro) { } else { msg.append(", "); } - msg.append(name == null ? "?" : name.toString() + new PyList(((PyType)unmerged).bases)); + msg.append( + name == null ? "?" : name.toString() + new PyList(((PyType) unmerged).bases)); } throw Py.TypeError(msg.toString()); } /** - * Finds the parent of type with an underlying_class or with slots sans a __dict__ - * slot. + * Finds the first super-type of the given {@code type} that is a "solid base" of the type, that + * is, the returned type has an {@link #underlying_class}, or it defines {@code __slots__} and + * no instance level dictionary ({@code __dict__} attribute). */ private static PyType solid_base(PyType type) { do { @@ -1110,38 +1849,48 @@ private static PyType solid_base(PyType type) { return PyObject.TYPE; } + /** + * A "solid base" is a type that has an {@link #underlying_class}, or defines {@code __slots__} + * and no instance level dictionary (no {@code __dict__} attribute). + */ private static boolean isSolidBase(PyType type) { - return type.underlying_class != null || (type.numSlots != 0 && !type.needs_userdict); + return type.underlying_class != null || (type.ownSlots != 0 && !type.needs_userdict); } /** - * Finds the base in bases with the most derived solid_base, ie the most base type + * Find the base selected from a {@link #bases} array that has the "most derived solid base". + * This will become the {@link #base} attribute of a class under construction, or in which the + * {@link #bases} tuple is being updated. On a successful return, the return value is one of the + * elements of the argument {@code bases} and the solid base of that return is a sub-type of the + * solid bases of all other (non-classic) elements of the argument. * * @throws Py.TypeError if the bases don't all derive from the same solid_base * @throws Py.TypeError if at least one of the bases isn't a new-style class */ private static PyType best_base(PyObject[] bases) { - PyType winner = null; - PyType candidate = null; - PyType best = null; - for (PyObject base : bases) { - if (base instanceof PyClass) { + PyType best = null; // The best base found so far + PyType bestSolid = null; // The solid base of the best base so far + for (PyObject b : bases) { + if (b instanceof PyType) { + PyType base = (PyType) b, solid = solid_base(base); + if (bestSolid == null) { + // First (non-classic) base we find becomes the best base so far + best = base; + bestSolid = solid; + } else if (bestSolid.isSubType(solid)) { + // Current best is still the best so far + } else if (solid.isSubType(bestSolid)) { + // base is better than the previous best since its solid base is more derived. + best = base; + bestSolid = solid; + } else { + throw Py.TypeError("multiple bases have instance lay-out conflict"); + } + } else if (b instanceof PyClass) { + // Skip over classic bases continue; - } - if (!(base instanceof PyType)) { - throw Py.TypeError("bases must be types"); - } - candidate = solid_base((PyType)base); - if (winner == null) { - winner = candidate; - best = (PyType)base; - } else if (winner.isSubType(candidate)) { - ; - } else if (candidate.isSubType(winner)) { - winner = candidate; - best = (PyType)base; } else { - throw Py.TypeError("multiple bases have instance lay-out conflict"); + throw Py.TypeError("bases must be types"); } } if (best == null) { @@ -1155,17 +1904,16 @@ private static boolean isJavaRootClass(PyType type) { } /** - * Finds the most derived subtype of initialMetatype in the types - * of bases, or initialMetatype if it is already the most derived. + * Finds the most derived subtype of initialMetatype in the types of bases, or initialMetatype + * if it is already the most derived. * - * @raises Py.TypeError if the all the metaclasses don't descend - * from the same base - * @raises Py.TypeError if one of the bases is a PyJavaClass or a - * PyClass with no proxyClass + * @raises Py.TypeError if the all the metaclasses don't descend from the same base + * @raises Py.TypeError if one of the bases is a PyJavaClass or a PyClass with no proxyClass */ private static PyType findMostDerivedMetatype(PyObject[] bases_list, PyType initialMetatype) { PyType winner = initialMetatype; - if (isJavaRootClass(winner)) { // consider this root class to be equivalent to type + if (isJavaRootClass(winner)) { + // consider this root class to be equivalent to type winner = PyType.TYPE; } @@ -1186,7 +1934,7 @@ private static PyType findMostDerivedMetatype(PyObject[] bases_list, PyType init continue; } throw Py.TypeError("metaclass conflict: the metaclass of a derived class must be a " - + "(non-strict) subclass of the metaclasses of all its bases"); + + "(non-strict) subclass of the metaclasses of all its bases"); } return winner; } @@ -1223,8 +1971,8 @@ public PyObject lookup(String name) { } /** - * Attribute lookup for name directly through mro objects' dicts. This isn't cached, - * and should generally only be used during the bootstrapping of a type. + * Attribute lookup for name directly through mro objects' dicts. This isn't cached, and should + * generally only be used during the bootstrapping of a type. * * @param name attribute name (must be interned) * @return found object or null @@ -1243,13 +1991,12 @@ protected PyObject lookup_mro(String name) { * @return found object or null */ public PyObject lookup_where(String name, PyObject[] where) { - if (methodCache == null) System.out.println("method cache is null"); - return methodCache.lookup_where(this, name, where); + return MethodCache.methodCache.lookup_where(this, name, where); } /** - * Attribute lookup for name through mro objects' dicts. This isn't cached, and should - * generally only be used during the bootstrapping of a type. + * Attribute lookup for name through mro objects' dicts. This isn't cached, and should generally + * only be used during the bootstrapping of a type. * * Returns where in the mro the attribute was found at where[0]. * @@ -1285,21 +2032,23 @@ public PyObject super_lookup(PyType ref, String name) { } int i; for (i = 0; i < mro.length; i++) { - if (mro[i] == ref) + if (mro[i] == ref) { break; + } } i++; for (; i < mro.length; i++) { if (mro[i] instanceof PyJavaType) { - // The MRO contains this proxy for classes extending a Java class and/or - // interfaces, but the proxy points back to this starting Python class. - // So break out of this infinite loop by ignoring this entry for super purposes. - // The use of super__ parallels the workaround seen in PyReflectedFunction - // Fixes http://bugs.jython.org/issue1540 - // Also ignore this if we're doing super during __init__ as we want it to behave - // Fixes http://bugs.jython.org/issue2375 - if(name != "__init__" && !name.startsWith("super__")) { - lookupName = "super__" + name; + /* + * The MRO contains this proxy for classes extending a Java class and/or interfaces, + * but the proxy points back to this starting Python class. So break out of this + * infinite loop by ignoring this entry for super purposes. The use of super__ + * parallels the workaround seen in PyReflectedFunction Fixes + * http://bugs.jython.org/issue1540 Also ignore this if we're doing super during + * __init__ as we want it to behave Fixes http://bugs.jython.org/issue2375 + */ + if (name != "__init__" && !name.startsWith("super__")) { + lookupName = "super__" + name; } else { lookupName = name; } @@ -1317,150 +2066,83 @@ public PyObject super_lookup(PyType ref, String name) { return null; } - public static void addBuilder(Class forClass, TypeBuilder builder) { - getClassToBuilder().put(forClass, builder); - - if (getClassToType().containsKey(forClass)) { - if (!BootstrapTypesSingleton.getInstance().remove(forClass)) { - Py.writeWarning("init", "Bootstrapping class not in BootstrapTypesSingleton.getClassToType()[class=" - + forClass + "]"); - } - // The types in BootstrapTypesSingleton.getClassToType() are initialized before their builders are assigned, - // so do the work of addFromClass & fillFromClass after the fact - fromClass(builder.getTypeClass()).init(builder.getTypeClass(), null); - } - } - - private static PyType addFromClass(Class c, Set needsInners) { - if (ExposeAsSuperclass.class.isAssignableFrom(c)) { - PyType exposedAs = fromClass(c.getSuperclass(), false); - PyType origExposedAs = getClassToType().putIfAbsent(c, exposedAs); - return exposedAs; - } - return createType(c, needsInners); - } - - static boolean hasBuilder(Class c) { - return getClassToBuilder().containsKey(c); + /** + * Register the {@link TypeBuilder} for the given class. This only really makes sense for a + * PyObject. Initialising a properly-formed PyObject will usually result in a call + * to addBuilder, thanks to code inserted by the Jython type-exposer. + * + * @param c class for which this is the builder + * @param builder to register + */ + public static void addBuilder(Class c, TypeBuilder builder) { + Registry.addBuilder(c, builder); } - - private static TypeBuilder getBuilder(Class c) { - if (c.isPrimitive() || !PyObject.class.isAssignableFrom(c)) { - // If this isn't a PyObject, don't bother forcing it to be initialized to load its - // builder - return null; - } - - // This is a PyObject, call forName to force static initialization on the class so if it has - // a builder, it'll be filled in - SecurityException exc = null; - try { - Class.forName(c.getName(), true, c.getClassLoader()); - } catch (ClassNotFoundException e) { - // Well, this is certainly surprising. - throw new RuntimeException("Got ClassNotFound calling Class.forName on an already " - + " found class.", e); - } catch (ExceptionInInitializerError e) { - throw Py.JavaError(e); - } catch (SecurityException e) { - exc = e; - } - TypeBuilder builder = getClassToBuilder().get(c); - if (builder == null && exc != null) { - Py.writeComment("type", - "Unable to initialize " + c.getName() + ", a PyObject subclass, due to a " + - "security exception, and no type builder could be found for it. If it's an " + - "exposed type, it may not work properly. Security exception: " + - exc.getMessage()); - } - return builder; - } - - private static PyType createType(Class c, Set needsInners) { -// System.out.println("createType c=" + c + ", needsInners=" + needsInners + ", BootstrapTypesSingleton.getInstance()=" + BootstrapTypesSingleton.getInstance()); - PyType newtype; - if (c == PyType.class) { - newtype = new PyType(false); - } else if (BootstrapTypesSingleton.getInstance().contains(c) || getBuilder(c) != null) { - newtype = new PyType(); - } else { - newtype = new PyJavaType(); - } - - // try to put the type into our cache but if one exists already ignore our new creation and instead return - // existing instance. This saves us from locking the whole createType and instead depend on the - // atomicity of putIfAbsent and finicky ordering :( - PyType type = getClassToType().putIfAbsent(c, newtype); - // synchronize on the c here to make sure the compiler does not re-order - synchronized (c) { - if (type != null) { - return type; - } - newtype.builtin = true; - newtype.init(c, needsInners); - newtype.invalidateMethodCache(); - return newtype; + /** + * Attempt to ensure that the that the type system has fully constructed the types necessary to + * build a fully-working, exposed, PyObject (the "bootstrap types"). Produce a + * warning message if it does not seem to have worked. This is called at the end of the static + * initialisation of PyObject. + * + * @return whether bootstrapping was successful + */ + public static synchronized boolean ensureBootstrapped() { + // Force bootstrap and collect any debris + Set> missing = Registry.bootstrap(); + if (!missing.isEmpty()) { + Py.writeWarning("init", + "Bootstrap types weren't encountered in bootstrapping: " + missing + + "\nThis may be caused by compiled core classes preceding " + + "their exposed equivalents on the class path."); + return false; } + return true; } - /* - Instead of using synchronization on the whole method we depend on IOD and putIfAbsent behaviour, - essentially letting the first type creation win and throwing away any concurrent ones. - This let's us have much more fine-grained locking. + /** + * Equivalent to {@link #fromClass(Class)}, which is to be preferred. + *

    + * The boolean argument is ignored. Previously it controlled whether the returned + * PyType remained strongly-reachable through a reference the type registry would + * keep. The returned object is now reachable as long as the class c remains + * loaded. + * + * @param c for which the corresponding PyType is to be found + * @param hardRef ignored + * @return the PyType found or created */ - - public static PyType fromClass(Class c) { - return fromClass(c, true); - } - public static PyType fromClass(Class c, boolean hardRef) { - PyType type = getClassToType().get(c); - if (type != null) { - // synchronize on the c here to make sure the compiler does not re-order - synchronized (c) { - return type; - } - } - // We haven't seen this class before, so its type needs to be created. If it's being - // exposed as a Java class, defer processing its inner types until it's completely - // created in case the inner class references a class that references this class. - Set needsInners = Generic.set(); - PyType result = addFromClass(c, needsInners); - for (PyJavaType javaType : needsInners) { - Class forClass = javaType.getProxyType(); - if (forClass == null) { - continue; - } - for (Class inner : forClass.getClasses()) { - // Only add the class if there isn't something else with that name and it came from this - // class - if (inner.getDeclaringClass() == forClass && - javaType.dict.__finditem__(inner.getSimpleName()) == null) { - // If this class is currently being loaded, any exposed types it contains won't have - // set their builder in PyType yet, so add them to BOOTSTRAP_TYPES so they're - // created as PyType instead of PyJavaType - if (inner.getAnnotation(ExposedType.class) != null - || ExposeAsSuperclass.class.isAssignableFrom(inner)) { - BootstrapTypesSingleton.getInstance().add(inner); - } - javaType.dict.__setitem__(inner.getSimpleName(), PyType.fromClass(inner, hardRef)); - } - } - } - if (hardRef && result != null) { - getExposedTypes().add(result) ; - } - - return result; + return fromClass(c); } - static PyType fromClassSkippingInners(Class c, Set needsInners) { - PyType type = getClassToType().get(c); - if (type != null) { - return type; + /** + * Look up (create if necessary) the PyType for the given target Java class. If the + * target's PyType already exists, this is returned quickly. When a + * PyType must be created, the method updates the registry of type information + * internal to Jython, caching the answer for next time. + *

    + * Creating the PyType also looks up or creates any PyTypes that the + * target depends upon, which results in re-entrant calls to fromClass for these + * classes and (if PyTypes are created for PyObjects) calls to + * {@link PyType#addBuilder(Class, TypeBuilder)}. + *

    + * Look-up of existing types is non-blocking in the majority of cases. + * + * @param c for which the corresponding PyType is to be found + * @return the PyType found or created + */ + public static PyType fromClass(Class c) { + try { + // Look up or create a Python type for c in the registry. + return Registry.classToType.get(c); + } catch (Registry.IncompleteType it) { + /* + * This *only* happens when called recursively during type construction, and therefore + * we can assume the caller is prepared to receive an incompletely constructed PyType as + * the answer. * + */ + return it.type; } - return addFromClass(c, needsInners); } @ExposedMethod(doc = BuiltinDocs.type___getattribute___doc) @@ -1473,6 +2155,7 @@ final PyObject type___getattribute__(PyObject name) { return ret; } + @Override public PyObject __findattr_ex__(String name) { return type___findattr_ex__(name); } @@ -1487,8 +2170,9 @@ final PyObject type___findattr_ex__(String name) { get = metaattr.implementsDescrGet(); if (useMetatypeFirst(metaattr) && get && metaattr.isDataDescr()) { PyObject res = metaattr.__get__(this, metatype); - if (res != null) + if (res != null) { return res; + } } } @@ -1525,8 +2209,9 @@ final void type___setattr__(PyObject name, PyObject value) { type___setattr__(asName(name), value); } + @Override public void __setattr__(String name, PyObject value) { - type___setattr__(name, value); + type___setattr__(name, value); } /** @@ -1547,8 +2232,8 @@ public void removeMethod(PyBuiltinMethod meth) { void type___setattr__(String name, PyObject value) { if (builtin) { - throw Py.TypeError(String.format("can't set attributes of built-in/extension type " - + "'%s'", this.name)); + throw Py.TypeError(String.format( + "can't set attributes of built-in/extension type " + "'%s'", this.name)); } super.__setattr__(name, value); postSetattr(name); @@ -1559,6 +2244,8 @@ void postSetattr(String name) { if (name == "__get__") { if (!hasGet && lookup("__get__") != null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean old = type.hasGet; type.hasGet = true; @@ -1569,6 +2256,8 @@ public boolean onType(PyType type) { } else if (name == "__set__") { if (!hasSet && lookup("__set__") != null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean old = type.hasSet; type.hasSet = true; @@ -1579,6 +2268,8 @@ public boolean onType(PyType type) { } else if (name == "__delete__") { if (!hasDelete && lookup("__delete__") != null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean old = type.hasDelete; type.hasDelete = true; @@ -1588,13 +2279,17 @@ public boolean onType(PyType type) { } } else if (name == "__getattribute__") { traverse_hierarchy(false, new OnType() { - public boolean onType(PyType type) { - return (type.usesObjectGetattribute = false); - } - }); + + @Override + public boolean onType(PyType type) { + return (type.usesObjectGetattribute = false); + } + + }); } } + @Override public void __delattr__(String name) { type___delattr__(name); } @@ -1604,13 +2299,12 @@ final void type___delattr__(PyObject name) { type___delattr__(asName(name)); } - protected void checkDelattr() { - } + protected void checkDelattr() {} void type___delattr__(String name) { if (builtin) { - throw Py.TypeError(String.format("can't set attributes of built-in/extension type " - + "'%s'", this.name)); + throw Py.TypeError(String.format( + "can't set attributes of built-in/extension type " + "'%s'", this.name)); } super.__delattr__(name); postDelattr(name); @@ -1621,6 +2315,8 @@ void postDelattr(String name) { if (name == "__get__") { if (hasGet && lookup("__get__") == null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean absent = type.getDict().__finditem__("__get__") == null; if (absent) { @@ -1634,6 +2330,8 @@ public boolean onType(PyType type) { } else if (name == "__set__") { if (hasSet && lookup("__set__") == null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean absent = type.getDict().__finditem__("__set__") == null; if (absent) { @@ -1647,6 +2345,8 @@ public boolean onType(PyType type) { } else if (name == "__delete__") { if (hasDelete && lookup("__delete__") == null) { traverse_hierarchy(false, new OnType() { + + @Override public boolean onType(PyType type) { boolean absent = type.getDict().__finditem__("__delete__") == null; if (absent) { @@ -1659,26 +2359,32 @@ public boolean onType(PyType type) { } } else if (name == "__getattribute__") { traverse_hierarchy(false, new OnType() { - public boolean onType(PyType type) { - return (type.usesObjectGetattribute = false); - } - }); + + @Override + public boolean onType(PyType type) { + return (type.usesObjectGetattribute = false); + } + + }); } } /** - * Invalidate this type's MethodCache entries. *Must* be called after any modification - * to __dict__ (or anything else affecting attribute lookups). + * Invalidate this type's MethodCache entries. *Must* be called after any modification to + * __dict__ (or anything else affecting attribute lookups). */ protected void invalidateMethodCache() { traverse_hierarchy(false, new OnType() { - public boolean onType(PyType type) { - type.versionTag = new Object(); - return false; - } - }); + + @Override + public boolean onType(PyType type) { + type.versionTag = new Object(); + return false; + } + }); } + @Override public PyObject __call__(PyObject[] args, String[] keywords) { return type___call__(args, keywords); } @@ -1691,16 +2397,19 @@ final PyObject type___call__(PyObject[] args, String[] keywords) { } PyObject obj = invokeNew(new_, this, true, args, keywords); - // When the call was type(something) or the returned object is not an instance of - // type, it won't be initialized + /* + * When the call was type(something) or the returned object is not an instance of type, it + * won't be initialized + */ if ((this == TYPE && args.length == 1 && keywords.length == 0) - || !obj.getType().isSubType(this)) { + || !obj.getType().isSubType(this)) { return obj; } obj.dispatch__init__(args, keywords); return obj; } + @Override protected void __rawdir__(PyDictionary accum) { mergeClassDict(accum, this); } @@ -1730,10 +2439,10 @@ public void pySetName(PyObject name) { // guarded by __setattr__ to prevent modification of builtins if (!(name instanceof PyString)) { throw Py.TypeError(String.format("can only assign string to %s.__name__, not '%s'", - this.name, name.getType().fastGetName())); + this.name, name.getType().fastGetName())); } String nameStr = name.toString(); - if (nameStr.indexOf((char)0) > -1) { + if (nameStr.indexOf((char) 0) > -1) { throw Py.ValueError("__name__ must not contain null bytes"); } setName(nameStr); @@ -1753,22 +2462,27 @@ public void pyDelName() { * Returns the actual dict underlying this type instance. Changes to Java types should go * through {@link #addMethod} and {@link #removeMethod}, or unexpected mro errors can occur. */ + @Override public PyObject fastGetDict() { return dict; } @ExposedGet(name = "__dict__") + @Override public PyObject getDict() { return new PyDictProxy(dict); } + @Override @ExposedSet(name = "__dict__") public void setDict(PyObject newDict) { // Analogous to CPython's descrobject:getset_set - throw Py.AttributeError(String.format("attribute '__dict__' of '%s' objects is not " - + "writable", getType().fastGetName())); + throw Py.AttributeError( + String.format("attribute '__dict__' of '%s' objects is not " + "writable", + getType().fastGetName())); } + @Override @ExposedDelete(name = "__dict__") public void delDict() { setDict(null); @@ -1794,9 +2508,10 @@ void setUsesObjectGetattribute(boolean usesObjectGetattribute) { this.usesObjectGetattribute = usesObjectGetattribute; } + @Override public Object __tojava__(Class c) { - if (underlying_class != null && (c == Object.class || c == Class.class || - c == Serializable.class)) { + if (underlying_class != null + && (c == Object.class || c == Class.class || c == Serializable.class)) { return underlying_class; } return super.__tojava__(c); @@ -1809,9 +2524,9 @@ public PyObject getModule() { } int lastDot = name.lastIndexOf('.'); if (lastDot != -1) { - return Py.newString(name.substring(0, lastDot)); + return new PyString(name.substring(0, lastDot)); } - return Py.newString("__builtin__"); + return new PyString("__builtin__"); } @ExposedDelete(name = "__module__") @@ -1822,7 +2537,7 @@ public void delModule() { @ExposedGet(name = "__abstractmethods__") public PyObject getAbstractmethods() { PyObject result = dict.__finditem__("__abstractmethods__"); - if (result == null) { + if (result == null || result instanceof PyDataDescr) { noAttributeError("__abstractmethods__"); } return result; @@ -1830,63 +2545,72 @@ public PyObject getAbstractmethods() { @ExposedSet(name = "__abstractmethods__") public void setAbstractmethods(PyObject value) { - // __abstractmethods__ should only be set once on a type, in abc.ABCMeta.__new__, - // so this function doesn't do anything special to update subclasses + /* + * __abstractmethods__ should only be set once on a type, in abc.ABCMeta.__new__, so this + * function doesn't do anything special to update subclasses + */ dict.__setitem__("__abstractmethods__", value); postSetattr("__abstractmethods__"); - tp_flags = value.__nonzero__() - ? tp_flags | Py.TPFLAGS_IS_ABSTRACT + tp_flags = value.__nonzero__() ? tp_flags | Py.TPFLAGS_IS_ABSTRACT : tp_flags & ~Py.TPFLAGS_IS_ABSTRACT; } - + public int getNumSlots() { return numSlots; } @ExposedMethod(names = "__repr__", doc = BuiltinDocs.type___repr___doc) final String type_toString() { - String kind; - if (!builtin) { - kind = "class"; + String kind = builtin ? "type" : "class"; + if (name == null || (!builtin && dict == null)) { + // Type not sufficiently ready to show as module.name (useful in debugging) + return String.format("<%s '%s'>", this.getClass().getSimpleName(), underlying_class); + } else if (Registry.deferredInit.contains(PyString.class)) { + // PyString not sufficiently ready to call this.getModule to show module.name + return String.format("<%s ... '%s'>", kind, name); } else { - kind = "type"; - } - PyObject module = getModule(); - if (module instanceof PyString && !module.toString().equals("__builtin__")) { - return String.format("<%s '%s.%s'>", kind, module.toString(), getName()); + // Normal path + PyObject module = getModule(); + if (module instanceof PyString && !module.toString().equals("__builtin__")) { + return String.format("<%s '%s.%s'>", kind, module.toString(), getName()); + } + return String.format("<%s '%s'>", kind, getName()); } - return String.format("<%s '%s'>", kind, getName()); } + @Override public String toString() { return type_toString(); } /** - * Raises AttributeError on type objects. The message differs from - * PyObject#noAttributeError, to mimic CPython behaviour. + * Raises AttributeError on type objects. The message differs from PyObject#noAttributeError, to + * mimic CPython behaviour. */ + @Override public void noAttributeError(String name) { throw Py.AttributeError(String.format("type object '%.50s' has no attribute '%.400s'", - fastGetName(), name)); + fastGetName(), name)); } - //XXX: consider pulling this out into a generally accessible place - // I bet this is duplicated more or less in other places. + /* + * XXX: consider pulling this out into a generally accessible place. I bet this is duplicated + * more or less in other places. + */ private static String confirmIdentifier(PyObject obj) { String identifier; if (!(obj instanceof PyString)) { throw Py.TypeError(String.format("__slots__ items must be strings, not '%.200s'", - obj.getType().fastGetName())); + obj.getType().fastGetName())); } else if (obj instanceof PyUnicode) { - identifier = ((PyUnicode)obj).encode(); + identifier = ((PyUnicode) obj).encode(); } else { identifier = obj.toString(); } String msg = "__slots__ must be identifiers"; if (identifier.length() == 0 - || (!Character.isLetter(identifier.charAt(0)) && identifier.charAt(0) != '_')) { + || (!Character.isLetter(identifier.charAt(0)) && identifier.charAt(0) != '_')) { throw Py.TypeError(msg); } for (char c : identifier.toCharArray()) { @@ -1897,11 +2621,13 @@ private static String confirmIdentifier(PyObject obj) { return identifier; } - //XXX: copied from CodeCompiler.java and changed variable names. - // Maybe this should go someplace for all classes to use. + /* + * XXX: copied from CodeCompiler.java and changed variable names. Maybe this should go someplace + * for all classes to use. + */ private static String mangleName(String classname, String methodname) { if (classname != null && methodname.startsWith("__") && !methodname.endsWith("__")) { - //remove leading '_' from classname + // remove leading '_' from classname int i = 0; while (classname.charAt(i) == '_') { i++; @@ -1930,8 +2656,10 @@ static class TypeResolver implements Serializable { private String name; TypeResolver(Class underlying_class, String module, String name) { - // Don't store the underlying_class for PyProxies as the proxy type needs to fill in - // based on the class, not be the class + /* + * Don't store the underlying_class for PyProxies as the proxy type needs to fill in + * based on the class, not be the class + */ if (underlying_class != null && !PyProxy.class.isAssignableFrom(underlying_class)) { this.underlying_class = underlying_class; } @@ -1941,7 +2669,7 @@ static class TypeResolver implements Serializable { private Object readResolve() { if (underlying_class != null) { - return PyType.fromClass(underlying_class, false); + return fromClass(underlying_class); } PyObject mod = imp.importName(module.intern(), false); PyObject pytyp = mod.__getattr__(name.intern()); @@ -2010,6 +2738,20 @@ public void removeFromUnmerged(PyJavaType winner) { } mro = newMro.toArray(new PyObject[newMro.size()]); } + + @Override + public String toString() { + List names = Generic.list(); + for (int i = next; i < mro.length; i++) { + PyObject t = mro[i]; + if (t instanceof PyType) { + names.add(((PyType) t).name); + } else { + names.add(t.toString()); + } + } + return names.toString(); + } } /** @@ -2017,6 +2759,9 @@ public void removeFromUnmerged(PyJavaType winner) { */ static class MethodCache { + /** Global mro cache. See {@link PyType#lookup_where(String, PyObject[])}. */ + private static final MethodCache methodCache = new MethodCache(); + /** The fixed size cache. */ private final AtomicReferenceArray table; @@ -2050,13 +2795,16 @@ public PyObject lookup_where(PyType type, String name, PyObject where[]) { } PyObject value = type.lookup_where_mro(name, where); if (isCacheableName(name)) { - // CAS isn't totally necessary here but is possibly more correct. Cache by - // the original version before the lookup, if it's changed since then - // we'll cache a bad entry. Bad entries and CAS failures aren't a concern - // as subsequent lookups will sort themselves out - table.compareAndSet(index, entry, new MethodCacheEntry(versionTag, name, where[0], - value)); + /* + * CAS isn't totally necessary here but is possibly more correct. Cache by the + * original version before the lookup, if it's changed since then we'll cache a bad + * entry. Bad entries and CAS failures aren't a concern as subsequent lookups will + * sort themselves out. + */ + table.compareAndSet(index, entry, + new MethodCacheEntry(versionTag, name, where[0], value)); } + return value; } @@ -2070,8 +2818,8 @@ private static int indexFor(Object version, String name) { /** * Determine if name is cacheable. * - * Since the cache can keep references to names alive longer than usual, it avoids - * caching unusually large strings. + * Since the cache can keep references to names alive longer than usual, it avoids caching + * unusually large strings. */ private static boolean isCacheableName(String name) { return name.length() <= 100; @@ -2114,47 +2862,6 @@ public PyObject get(PyObject[] where) { } } - /** - * - * Using the IOD http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl - * to reduce the risk for race conditions in a few of our fields - * - */ - - /** - * Mapping of Java classes to their PyTypes. - */ - private static class LazyClassToTypeHolder { - private static ConcurrentMap, PyType> classToType = new MapMaker().weakKeys().weakValues().makeMap(); - - } - - private static ConcurrentMap, PyType> getClassToType() { - return LazyClassToTypeHolder.classToType; - } - - /** - * Mapping of Java classes to their TypeBuilders. - */ - private static class LazyClassToBuilderHolder { - private static ConcurrentMap, TypeBuilder> classToBuilder = Generic.concurrentMap(); - } - - private static ConcurrentMap, TypeBuilder> getClassToBuilder() { - return LazyClassToBuilderHolder.classToBuilder; - } - - /** - * Set of exposed types - */ - private static class LazyExposedTypes { - private static Set exposedTypes = Generic.set(); - } - - private static Set getExposedTypes() { - return LazyExposedTypes.exposedTypes; - } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { @@ -2165,8 +2872,8 @@ public int traverse(Visitproc visit, Object arg) { return retVal; } } - //bases cannot be null - for (PyObject ob: bases) { + // bases cannot be null + for (PyObject ob : bases) { if (ob != null) { retVal = visit.visit(ob, arg); if (retVal != 0) { @@ -2181,16 +2888,16 @@ public int traverse(Visitproc visit, Object arg) { } } if (mro != null) { - for (PyObject ob: mro) { + for (PyObject ob : mro) { retVal = visit.visit(ob, arg); if (retVal != 0) { return retVal; } } } - //don't traverse subclasses since they are weak refs. - //ReferenceQueue subclasses_refq = new ReferenceQueue(); - //Set> subclasses = Generic.set(); + // Don't traverse subclasses since they are weak refs. + // ReferenceQueue subclasses_refq = new ReferenceQueue(); + // Set> subclasses = Generic.set(); return 0; } @@ -2199,14 +2906,14 @@ public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationExceptio if (ob == null) { return false; } - //bases cannot be null - for (PyObject obj: bases) { + // bases cannot be null + for (PyObject obj : bases) { if (obj == ob) { return true; } } if (mro != null) { - for (PyObject obj: mro) { + for (PyObject obj : mro) { if (obj == ob) { return true; } diff --git a/src/org/python/core/PyUnicode.java b/src/org/python/core/PyUnicode.java index a128e7d74..b649e2989 100644 --- a/src/org/python/core/PyUnicode.java +++ b/src/org/python/core/PyUnicode.java @@ -8,8 +8,6 @@ import java.util.List; import java.util.Set; -import com.google.common.base.CharMatcher; - import org.python.core.stringlib.FieldNameIterator; import org.python.core.stringlib.MarkupIterator; import org.python.expose.ExposedMethod; @@ -19,12 +17,14 @@ import org.python.modules._codecs; import org.python.util.Generic; +import com.google.common.base.CharMatcher; + /** * a builtin python unicode string. */ @Untraversable @ExposedType(name = "unicode", base = PyBaseString.class, doc = BuiltinDocs.unicode_doc) -public class PyUnicode extends PyString implements Iterable { +public class PyUnicode extends PyString implements Iterable { /** * Nearly every significant method comes in two versions: one applicable when the string @@ -89,7 +89,7 @@ public PyUnicode(int[] codepoints) { } PyUnicode(StringBuilder buffer) { - this(TYPE, new String(buffer)); + this(TYPE, buffer.toString()); } private static StringBuilder fromCodePoints(Iterator iter) { @@ -134,6 +134,18 @@ public int[] toCodePoints() { return codePoints; } + /** + * {@code PyUnicode} implements the interface {@link BufferProtocol} technically by inheritance from {@link PyString}, + * but does not provide a buffer (in CPython). We therefore arrange that all calls to {@code getBuffer} + * raise an error. + * + * @return always throws a {@code ClassCastException} + */ + @Override + public synchronized PyBuffer getBuffer(int flags) throws ClassCastException { + throw new ClassCastException("'unicode' does not support the buffer protocol"); + } + // ------------------------------------------------------------------------------------------ // Index translation for Unicode beyond the BMP // ------------------------------------------------------------------------------------------ @@ -156,7 +168,7 @@ private interface IndexTranslator extends Serializable { /** * The instance of index translation in use in this string. It will be set to either - * {@link #BASIC} or and instance of {@link #Supplementary}. + * {@link #BASIC} or an instance of {@link PyUnicode.Supplementary}. */ private final IndexTranslator translator; @@ -468,7 +480,7 @@ private static int[] getSupplementaryCounts(final String string) { * @param string of UTF-16 code units * @param p index into that string * @return 2 if a surrogate pair stands at p, 1 if not - * @throws PyException(ValueError) if a lone surrogate stands at p. + * @throws PyException {@code ValueError} if a lone surrogate stands at p. */ private static int calcAdvance(String string, int p) throws PyException { @@ -583,7 +595,7 @@ public int getCodePointCount() { } public static String checkEncoding(String s) { - if (s == null || CharMatcher.ASCII.matchesAllOf(s)) { + if (s == null || CharMatcher.ascii().matchesAllOf(s)) { return s; } return codecs.PyUnicode_EncodeASCII(s, s.length(), null); @@ -592,9 +604,8 @@ public static String checkEncoding(String s) { @ExposedNew final static PyObject unicode_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { - ArgParser ap = - new ArgParser("unicode", args, keywords, new String[] {"string", "encoding", - "errors"}, 0); + ArgParser ap = new ArgParser("unicode", args, keywords, + new String[] {"string", "encoding", "errors"}, 0); PyObject S = ap.getPyObject(0, null); String encoding = checkEncoding(ap.getString(1, null)); String errors = checkEncoding(ap.getString(2, null)); @@ -603,15 +614,15 @@ final static PyObject unicode_new(PyNewWrapper new_, boolean init, PyType subtyp return new PyUnicode(""); } if (S instanceof PyUnicode) { - return new PyUnicode(((PyUnicode)S).getString()); + return new PyUnicode(((PyUnicode) S).getString()); } if (S instanceof PyString) { if (S.getType() != PyString.TYPE && encoding == null && errors == null) { return S.__unicode__(); } - PyObject decoded = codecs.decode((PyString)S, encoding, errors); + PyObject decoded = codecs.decode((PyString) S, encoding, errors); if (decoded instanceof PyUnicode) { - return new PyUnicode((PyUnicode)decoded); + return new PyUnicode((PyUnicode) decoded); } else { throw Py.TypeError("decoder did not return an unicode object (type=" + decoded.getType().fastGetName() + ")"); @@ -623,7 +634,7 @@ final static PyObject unicode_new(PyNewWrapper new_, boolean init, PyType subtyp return new PyUnicodeDerived(subtype, Py.EmptyString); } if (S instanceof PyUnicode) { - return new PyUnicodeDerived(subtype, (PyUnicode)S); + return new PyUnicodeDerived(subtype, (PyUnicode) S); } else { return new PyUnicodeDerived(subtype, S.__str__()); } @@ -713,22 +724,107 @@ protected PyObject getslice(int start, int stop, int step) { for (Iterator iter = newSubsequenceIterator(start, stop, step); iter.hasNext();) { buffer.appendCodePoint(iter.next()); } - return createInstance(new String(buffer)); + return createInstance(buffer.toString()); } - @ExposedMethod(type = MethodType.CMP, doc = BuiltinDocs.unicode___getslice___doc) + @ExposedMethod(type = MethodType.CMP) final int unicode___cmp__(PyObject other) { + // XXX needs proper coercion like __eq__, then UCS-32 code point order :( return str___cmp__(other); } - @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___getslice___doc) + @Override + public PyObject __eq__(PyObject other) { + return unicode___eq__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___eq___doc) final PyObject unicode___eq__(PyObject other) { - return str___eq__(other); + try { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().equals(s) ? Py.True : Py.False; + } catch (PyException e) { + // Decoding failed: treat as unequal + return Py.False; + } } - @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___getslice___doc) + @Override + public PyObject __ne__(PyObject other) { + return unicode___ne__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___ne___doc) final PyObject unicode___ne__(PyObject other) { - return str___ne__(other); + try { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().equals(s) ? Py.False : Py.True; + } catch (PyException e) { + // Decoding failed: treat as unequal + return Py.True; + } + } + + @Override + public PyObject __lt__(PyObject other) { + return unicode___lt__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___lt___doc) + final PyObject unicode___lt__(PyObject other) { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().compareTo(s) < 0 ? Py.True : Py.False; + } + + @Override + public PyObject __le__(PyObject other) { + return unicode___le__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___le___doc) + final PyObject unicode___le__(PyObject other) { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().compareTo(s) <= 0 ? Py.True : Py.False; + } + + @Override + public PyObject __gt__(PyObject other) { + return unicode___gt__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___gt___doc) + final PyObject unicode___gt__(PyObject other) { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().compareTo(s) > 0 ? Py.True : Py.False; + } + + @Override + public PyObject __ge__(PyObject other) { + return unicode___ge__(other); + } + + @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___ge___doc) + final PyObject unicode___ge__(PyObject other) { + String s = coerceForComparison(other); + if (s == null) { + return null; + } + return getString().compareTo(s) >= 0 ? Py.True : Py.False; } @ExposedMethod(doc = BuiltinDocs.unicode___hash___doc) @@ -822,7 +918,7 @@ public void remove() { } } - private static class SteppedIterator implements Iterator { + private static class SteppedIterator implements Iterator { private final Iterator iter; private final int step; @@ -885,14 +981,14 @@ public Iterator newSubsequenceIterator() { public Iterator newSubsequenceIterator(int start, int stop, int step) { if (isBasicPlane()) { if (step < 0) { - return new SteppedIterator(step * -1, new ReversedIterator( + return new SteppedIterator(step * -1, new ReversedIterator( new SubsequenceIteratorBasic(stop + 1, start + 1, 1))); } else { return new SubsequenceIteratorBasic(start, stop, step); } } else { if (step < 0) { - return new SteppedIterator(step * -1, new ReversedIterator( + return new SteppedIterator(step * -1, new ReversedIterator( new SubsequenceIteratorImpl(stop + 1, start + 1, 1))); } else { return new SubsequenceIteratorImpl(start, stop, step); @@ -901,53 +997,158 @@ public Iterator newSubsequenceIterator(int start, int stop, int step) { } /** - * Helper used many times to "coerce" a method argument into a PyUnicode (which it - * may already be). A null or incoercible argument will raise a - * TypeError. + * Interpret the object as a Java String representing characters as UTF-16, or + * return null if the type does not admit this conversion. From a + * PyUnicode we return its internal string. A byte argument is decoded with the + * default encoding. * * @param o the object to coerce - * @return an equivalent PyUnicode (or o itself) + * @return an equivalent String */ - private PyUnicode coerceToUnicode(PyObject o) { + private static String coerceToStringOrNull(PyObject o) { if (o instanceof PyUnicode) { - return (PyUnicode)o; + return ((PyUnicode) o).getString(); } else if (o instanceof PyString) { - return new PyUnicode(((PyString)o).getString(), true); + return ((PyString) o).decode().toString(); } else if (o instanceof BufferProtocol) { // PyByteArray, PyMemoryView, Py2kBuffer ... - try (PyBuffer buf = ((BufferProtocol)o).getBuffer(PyBUF.FULL_RO)) { - return new PyUnicode(buf.toString(), true); + // We ought to be able to call codecs.decode on o but see Issue #2164 + try (PyBuffer buf = ((BufferProtocol) o).getBuffer(PyBUF.FULL_RO)) { + PyString s = new PyString(buf); + // For any sensible codec, the return is unicode and toString() is getString(). + return s.decode().toString(); } } else { // o is some type not allowed: - if (o == null) { - // Do something safe and approximately right - o = Py.None; + return null; + } + } + + /** + * Interpret the object as a Java String for use in comparison. The return + * represents characters as UTF-16. From a PyUnicode we return its internal string. + * A str and buffer argument is decoded with the default encoding. + *

    + * This method could be replaced by {@link #coerceToStringOrNull(PyObject)} if we were content + * to allowing a wider range of types to be supported in comparison operations than (C)Python + * unicode.__eq__. + * + * @param o the object to coerce + * @return an equivalent String + */ + private static String coerceForComparison(PyObject o) { + if (o instanceof PyUnicode) { + return ((PyUnicode) o).getString(); + } else if (o instanceof PyString) { + return ((PyString) o).decode().toString(); + } else if (o instanceof Py2kBuffer) { + // We ought to be able to call codecs.decode on o but see Issue #2164 + try (PyBuffer buf = ((BufferProtocol) o).getBuffer(PyBUF.FULL_RO)) { + PyString s = new PyString(buf); + // For any sensible codec, the return is unicode and toString() is getString(). + return s.decode().toString(); } - throw Py.TypeError("coercing to Unicode: need string or buffer, " - + o.getType().fastGetName() + " found"); + } else { + // o is some type not allowed: + return null; } } /** - * Helper used many times to "coerce" a method argument into a PyUnicode (which it - * may already be). A null argument or a PyNone causes - * null to be returned. + * Interpret the object as a Java String representing characters as UTF-16, or + * raise an error if the type does not admit this conversion. A byte argument is decoded with + * the default encoding. * * @param o the object to coerce - * @return an equivalent PyUnicode (or o itself, or null) + * @return an equivalent String (and never null) */ - private PyUnicode coerceToUnicodeOrNull(PyObject o) { - if (o == null || o == Py.None) { + private static String coerceToString(PyObject o) { + String s = coerceToStringOrNull(o); + if (s == null) { + throw errorCoercingToUnicode(o); + } + return s; + } + + /** + * Interpret the object as a Java String representing characters as UTF-16, or + * optionally as null (for a null or None argument if the + * second argument is true). Raise an error if the type does not admit this + * conversion. + * + * @param o the object to coerce + * @param allowNullArgument iff true allow a null or none argument + * @return an equivalent String or null + */ + private static String coerceToString(PyObject o, boolean allowNullArgument) { + if (allowNullArgument && (o == null || o == Py.None)) { return null; } else { - return coerceToUnicode(o); + return coerceToString(o); + } + } + + /** Construct exception "coercing to Unicode: ..." */ + private static PyException errorCoercingToUnicode(PyObject o) { + return Py.TypeError("coercing to Unicode: need string or buffer, " + + (o == null ? Py.None : o).getType().fastGetName() + " found"); + } + + /** + * Interpret the object as a PyUnicode, or return null if the type + * does not admit this conversion. From a PyUnicode we return itself. A byte + * argument is decoded with the default encoding. + * + * @param o the object to coerce + * @return an equivalent PyUnicode (or o itself) + */ + private static PyUnicode coerceToUnicodeOrNull(PyObject o) { + if (o instanceof PyUnicode) { + return (PyUnicode) o; + } else if (o instanceof PyString) { + // For any sensible codec, the return here is unicode. + PyObject u = ((PyString) o).decode(); + return (u instanceof PyUnicode) ? (PyUnicode) u : new PyUnicode(o.toString()); + } else if (o instanceof BufferProtocol) { + // PyByteArray, PyMemoryView, Py2kBuffer ... + // We ought to be able to call codecs.decode on o but see Issue #2164 + try (PyBuffer buf = ((BufferProtocol) o).getBuffer(PyBUF.FULL_RO)) { + PyString s = new PyString(buf); + // For any sensible codec, the return is unicode and toString() is getString(). + PyObject u = s.decode(); + return (u instanceof PyUnicode) ? (PyUnicode) u : new PyUnicode(o.toString()); + } + } else { + // o is some type not allowed: + return null; } } + /** + * Interpret the object as a PyUnicode, or raise a TypeError if the + * type does not admit this conversion. From a PyUnicode we return itself. A byte + * argument is decoded with the default encoding. + * + * @param o the object to coerce + * @return an equivalent PyUnicode (or o itself) + */ + private static PyUnicode coerceToUnicode(PyObject o) { + PyUnicode u = coerceToUnicodeOrNull(o); + if (u == null) { + throw errorCoercingToUnicode(o); + } + return u; + } + + @Override + public boolean __contains__(PyObject o) { + return unicode___contains__(o); + } + @ExposedMethod(doc = BuiltinDocs.unicode___contains___doc) final boolean unicode___contains__(PyObject o) { - return str___contains__(o); + String other = coerceToString(o); + return getString().indexOf(other) >= 0; } @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___getslice___doc) @@ -967,15 +1168,9 @@ public PyObject __add__(PyObject other) { @ExposedMethod(type = MethodType.BINARY, doc = BuiltinDocs.unicode___getslice___doc) final PyObject unicode___add__(PyObject other) { - PyUnicode otherUnicode; - if (other instanceof PyUnicode) { - otherUnicode = (PyUnicode)other; - } else if (other instanceof PyString) { - otherUnicode = (PyUnicode)((PyString)other).decode(); - } else { - return null; - } - return new PyUnicode(getString().concat(otherUnicode.getString())); + // Interpret other as a Java String + String s = coerceToStringOrNull(other); + return s == null ? null : new PyUnicode(getString().concat(s)); } @ExposedMethod(doc = BuiltinDocs.unicode_lower_doc) @@ -1026,7 +1221,16 @@ final PyObject unicode_swapcase() { return new PyUnicode(buffer); } - private static class StripIterator implements Iterator { + /** Define what characters are to be treated as a space according to Python 2. */ + private static boolean isPythonSpace(int ch) { + // Use the Java built-in methods as far as possible + return Character.isWhitespace(ch) // catches the ASCII spaces and some others + || Character.isSpaceChar(ch) // catches remaining Unicode spaces + || ch == 0x0085 // NEXT LINE (not a space in Java) + || ch == 0x180e; // MONGOLIAN VOWEL SEPARATOR (not a space in Java 9+ or Python 3) + } + + private static class StripIterator implements Iterator { private final Iterator iter; private int lookahead = -1; @@ -1048,7 +1252,7 @@ public StripIterator(PyUnicode sep, Iterator iter) { } else { while (iter.hasNext()) { int codePoint = iter.next(); - if (!Character.isWhitespace(codePoint)) { + if (!isPythonSpace(codePoint)) { lookahead = codePoint; return; } @@ -1062,7 +1266,7 @@ public boolean hasNext() { } @Override - public Object next() { + public Integer next() { int old = lookahead; if (iter.hasNext()) { lookahead = iter.next(); @@ -1078,36 +1282,37 @@ public void remove() { } } - // compliance requires that we need to support a bit of inconsistency - // compared to other coercion used + // Compliance requires a bit of inconsistency with other coercions used. /** * Helper used in .strip() to "coerce" a method argument into a * PyUnicode (which it may already be). A null argument or a * PyNone causes null to be returned. A buffer type is not acceptable * to (Unicode) .strip(). This is the difference from - * {@link #coerceToUnicodeOrNull(PyObject)}. + * {@link #coerceToUnicode(PyObject, boolean)}. * * @param o the object to coerce + * @param name of method * @return an equivalent PyUnicode (or o itself, or null) */ - private PyUnicode coerceStripSepToUnicode(PyObject o) { + private static PyUnicode coerceStripSepToUnicode(PyObject o, String name) { if (o == null) { return null; } else if (o instanceof PyUnicode) { - return (PyUnicode)o; + return (PyUnicode) o; } else if (o instanceof PyString) { - return new PyUnicode(((PyString)o).decode().toString()); + PyObject u = ((PyString) o).decode(); + return (u instanceof PyUnicode) ? (PyUnicode) u : new PyUnicode(u.toString()); } else if (o == Py.None) { return null; } else { - throw Py.TypeError("strip arg must be None, unicode or str"); + throw Py.TypeError(name + " arg must be None, unicode or str"); } } @ExposedMethod(defaults = "null", doc = BuiltinDocs.unicode_strip_doc) final PyObject unicode_strip(PyObject sepObj) { - PyUnicode sep = coerceStripSepToUnicode(sepObj); + PyUnicode sep = coerceStripSepToUnicode(sepObj, "strip"); if (isBasicPlane()) { // this contains only basic plane characters @@ -1121,14 +1326,14 @@ final PyObject unicode_strip(PyObject sepObj) { } // Not basic plane: have to do real Unicode - return new PyUnicode(new ReversedIterator(new StripIterator(sep, new ReversedIterator( - new StripIterator(sep, newSubsequenceIterator()))))); + return new PyUnicode(new ReversedIterator(new StripIterator(sep, + new ReversedIterator<>(new StripIterator(sep, newSubsequenceIterator()))))); } @ExposedMethod(defaults = "null", doc = BuiltinDocs.unicode_lstrip_doc) final PyObject unicode_lstrip(PyObject sepObj) { - PyUnicode sep = coerceStripSepToUnicode(sepObj); + PyUnicode sep = coerceStripSepToUnicode(sepObj, "lstrip"); if (isBasicPlane()) { // this contains only basic plane characters @@ -1148,7 +1353,7 @@ final PyObject unicode_lstrip(PyObject sepObj) { @ExposedMethod(defaults = "null", doc = BuiltinDocs.unicode_rstrip_doc) final PyObject unicode_rstrip(PyObject sepObj) { - PyUnicode sep = coerceStripSepToUnicode(sepObj); + PyUnicode sep = coerceStripSepToUnicode(sepObj, "rstrip"); if (isBasicPlane()) { // this contains only basic plane characters @@ -1162,8 +1367,32 @@ final PyObject unicode_rstrip(PyObject sepObj) { } // Not basic plane: have to do real Unicode - return new PyUnicode(new ReversedIterator(new StripIterator(sep, new ReversedIterator( - newSubsequenceIterator())))); + return new PyUnicode(new ReversedIterator( + new StripIterator(sep, new ReversedIterator<>(newSubsequenceIterator())))); + } + + /** {@inheritDoc} */ + @Override + protected int _findLeft(int right) { + String s = getString(); + for (int left = 0; left < right; left++) { + if (!isPythonSpace(s.charAt(left))) { + return left; + } + } + return right; + } + + /** {@inheritDoc} */ + @Override + protected int _findRight() { + String s = getString(); + for (int right = s.length(); --right >= 0;) { + if (!isPythonSpace(s.charAt(right))) { + return right; + } + } + return -1; } @Override @@ -1176,7 +1405,7 @@ final PyTuple unicode_partition(PyObject sep) { return unicodePartition(coerceToUnicode(sep)); } - private abstract class SplitIterator implements Iterator { + private abstract class SplitIterator implements Iterator { protected final int maxsplit; protected final Iterator iter = newSubsequenceIterator(); @@ -1234,7 +1463,7 @@ public PyUnicode next() { while (iter.hasNext()) { int codepoint = iter.next(); - if (Character.isWhitespace(codepoint)) { + if (isPythonSpace(codepoint)) { completeSeparator = true; if (!atBeginning) { inSeparator = true; @@ -1254,7 +1483,7 @@ public PyUnicode next() { } } - private static class PeekIterator implements Iterator { + private static class PeekIterator implements Iterator { private T lookahead = null; private final Iterator iter; @@ -1286,7 +1515,7 @@ public void remove() { } } - private static class ReversedIterator implements Iterator { + private static class ReversedIterator implements Iterator { private final List reversed = Generic.list(); private final Iterator iter; @@ -1315,9 +1544,9 @@ public void remove() { } } - private class LineSplitIterator implements Iterator { + private class LineSplitIterator implements Iterator { - private final PeekIterator iter = new PeekIterator(newSubsequenceIterator()); + private final PeekIterator iter = new PeekIterator<>(newSubsequenceIterator()); private final boolean keepends; LineSplitIterator(boolean keepends) { @@ -1330,7 +1559,7 @@ public boolean hasNext() { } @Override - public Object next() { + public PyObject next() { StringBuilder buffer = new StringBuilder(); while (iter.hasNext()) { int codepoint = iter.next(); @@ -1432,28 +1661,150 @@ final PyTuple unicode_rpartition(PyObject sep) { @ExposedMethod(defaults = {"null", "-1"}, doc = BuiltinDocs.unicode_split_doc) final PyList unicode_split(PyObject sepObj, int maxsplit) { - PyUnicode sep = coerceToUnicodeOrNull(sepObj); + String sep = coerceToString(sepObj, true); if (sep != null) { - return _split(sep.getString(), maxsplit); + return _split(sep, maxsplit); } else { return _split(null, maxsplit); } } + /** + * {@inheritDoc} The split sections will be {@link PyUnicode} and use the Python + * unicode definition of "space". + */ + @Override + protected PyList splitfields(int maxsplit) { + /* + * Result built here is a list of split parts, exactly as required for s.split(None, + * maxsplit). If there are to be n splits, there will be n+1 elements in L. + */ + PyList list = new PyList(); + + String s = getString(); + int length = s.length(), start = 0, splits = 0, index; + + if (maxsplit < 0) { + // Make all possible splits: there can't be more than: + maxsplit = length; + } + + // start is always the first character not consumed into a piece on the list + while (start < length) { + + // Find the next occurrence of non-whitespace + while (start < length) { + if (!isPythonSpace(s.charAt(start))) { + // Break leaving start pointing at non-whitespace + break; + } + start++; + } + + if (start >= length) { + // Only found whitespace so there is no next segment + break; + + } else if (splits >= maxsplit) { + // The next segment is the last and contains all characters up to the end + index = length; + + } else { + // The next segment runs up to the next next whitespace or end + for (index = start; index < length; index++) { + if (isPythonSpace(s.charAt(index))) { + // Break leaving index pointing at whitespace + break; + } + } + } + + // Make a piece from start up to index + list.append(fromSubstring(start, index)); + splits++; + + // Start next segment search at that point + start = index; + } + + return list; + } + @ExposedMethod(defaults = {"null", "-1"}, doc = BuiltinDocs.unicode_rsplit_doc) final PyList unicode_rsplit(PyObject sepObj, int maxsplit) { - PyUnicode sep = coerceToUnicodeOrNull(sepObj); + String sep = coerceToString(sepObj, true); if (sep != null) { - return _rsplit(sep.getString(), maxsplit); + return _rsplit(sep, maxsplit); } else { return _rsplit(null, maxsplit); } } + /** + * {@inheritDoc} The split sections will be {@link PyUnicode} and use the Python + * unicode definition of "space". + */ + @Override + protected PyList rsplitfields(int maxsplit) { + /* + * Result built here (in reverse) is a list of split parts, exactly as required for + * s.rsplit(None, maxsplit). If there are to be n splits, there will be n+1 elements. + */ + PyList list = new PyList(); + + String s = getString(); + int length = s.length(), end = length - 1, splits = 0, index; + + if (maxsplit < 0) { + // Make all possible splits: there can't be more than: + maxsplit = length; + } + + // end is always the rightmost character not consumed into a piece on the list + while (end >= 0) { + + // Find the next occurrence of non-whitespace (working leftwards) + while (end >= 0) { + if (!isPythonSpace(s.charAt(end))) { + // Break leaving end pointing at non-whitespace + break; + } + --end; + } + + if (end < 0) { + // Only found whitespace so there is no next segment + break; + + } else if (splits >= maxsplit) { + // The next segment is the last and contains all characters back to the beginning + index = -1; + + } else { + // The next segment runs back to the next next whitespace or beginning + for (index = end; index >= 0; --index) { + if (isPythonSpace(s.charAt(index))) { + // Break leaving index pointing at whitespace + break; + } + } + } + + // Make a piece from index+1 start up to end+1 + list.append(fromSubstring(index + 1, end + 1)); + splits++; + + // Start next segment search at that point + end = index; + } + + list.reverse(); + return list; + } + @ExposedMethod(defaults = "false", doc = BuiltinDocs.unicode___getslice___doc) final PyList unicode_splitlines(boolean keepends) { return new PyList(new LineSplitIterator(keepends)); - } @Override @@ -1464,16 +1815,16 @@ protected PyString fromSubstring(int begin, int end) { @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_index_doc) final int unicode_index(PyObject subObj, PyObject start, PyObject end) { - final PyUnicode sub = coerceToUnicode(subObj); - // Now use the mechanics of the PyString on the UTF-16 of the PyUnicode. - return checkIndex(_find(sub.getString(), start, end)); + final String sub = coerceToString(subObj); + // Now use the mechanics of the PyString on the UTF-16. + return checkIndex(_find(sub, start, end)); } @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_index_doc) final int unicode_rindex(PyObject subObj, PyObject start, PyObject end) { - final PyUnicode sub = coerceToUnicode(subObj); - // Now use the mechanics of the PyString on the UTF-16 of the PyUnicode. - return checkIndex(_rfind(sub.getString(), start, end)); + final String sub = coerceToString(subObj); + // Now use the mechanics of the PyString on the UTF-16. + return checkIndex(_rfind(sub, start, end)); } @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_count_doc) @@ -1484,8 +1835,8 @@ final int unicode_count(PyObject subObj, PyObject start, PyObject end) { } int[] indices = super.translateIndices(start, end); // do not convert to utf-16 indices. int count = 0; - for (Iterator mainIter = newSubsequenceIterator(indices[0], indices[1], 1); mainIter - .hasNext();) { + for (Iterator mainIter = + newSubsequenceIterator(indices[0], indices[1], 1); mainIter.hasNext();) { int matched = sub.getCodePointCount(); for (Iterator subIter = sub.newSubsequenceIterator(); mainIter.hasNext() && subIter.hasNext();) { @@ -1493,7 +1844,6 @@ final int unicode_count(PyObject subObj, PyObject start, PyObject end) { break; } matched--; - } if (matched == 0) { count++; @@ -1504,13 +1854,13 @@ final int unicode_count(PyObject subObj, PyObject start, PyObject end) { @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_find_doc) final int unicode_find(PyObject subObj, PyObject start, PyObject end) { - int found = _find(coerceToUnicode(subObj).getString(), start, end); + int found = _find(coerceToString(subObj), start, end); return found < 0 ? -1 : translator.codePointIndex(found); } @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_rfind_doc) final int unicode_rfind(PyObject subObj, PyObject start, PyObject end) { - int found = _rfind(coerceToUnicode(subObj).getString(), start, end); + int found = _rfind(coerceToString(subObj), start, end); return found < 0 ? -1 : translator.codePointIndex(found); } @@ -1661,7 +2011,7 @@ final PyString unicode_replace(PyObject oldPieceObj, PyObject newPieceObj, int c SplitIterator iter = newSplitIterator(oldPiece, count); int numSplits = 0; while (iter.hasNext()) { - buffer.append(((PyUnicode)iter.next()).getString()); + buffer.append(((PyUnicode) iter.next()).getString()); if (iter.hasNext()) { buffer.append(newPiece.getString()); } @@ -1686,14 +2036,89 @@ final PyUnicode unicode_join(PyObject seq) { return unicodeJoin(seq); } + /** + * Equivalent to the Python unicode.startswith method, testing whether a string + * starts with a specified prefix, where a sub-range is specified by [start:end]. + * Arguments start and end are interpreted as in slice notation, with + * null or {@link Py#None} representing "missing". prefix can also be a tuple of + * prefixes to look for. + * + * @param prefix string to check for (or a PyTuple of them). + * @param start start of slice. + * @param end end of slice. + * @return true if this string slice starts with a specified prefix, otherwise + * false. + */ + @Override + public boolean startswith(PyObject prefix, PyObject start, PyObject end) { + return unicode_startswith(prefix, start, end); + } + @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_startswith_doc) - final boolean unicode_startswith(PyObject prefix, PyObject start, PyObject end) { - return str_startswith(prefix, start, end); + final boolean unicode_startswith(PyObject prefix, PyObject startObj, PyObject endObj) { + int[] indices = translateIndices(startObj, endObj); + int start = indices[0]; + int sliceLen = indices[1] - start; + + if (!(prefix instanceof PyTuple)) { + // It ought to be PyUnicode or some kind of bytes with the buffer API to decode. + String s = coerceToString(prefix); + return sliceLen >= s.length() && getString().startsWith(s, start); + + } else { + // Loop will return true if this slice starts with any prefix in the tuple + for (PyObject prefixObj : ((PyTuple) prefix).getArray()) { + // It ought to be PyUnicode or some kind of bytes with the buffer API. + String s = coerceToString(prefixObj); + if (sliceLen >= s.length() && getString().startsWith(s, start)) { + return true; + } + } + // None matched + return false; + } + } + + /** + * Equivalent to the Python unicode.endswith method, testing whether a string ends + * with a specified suffix, where a sub-range is specified by [start:end]. + * Arguments start and end are interpreted as in slice notation, with + * null or {@link Py#None} representing "missing". suffix can also be a tuple of + * suffixes to look for. + * + * @param suffix string to check for (or a PyTuple of them). + * @param start start of slice. + * @param end end of slice. + * @return true if this string slice ends with a specified suffix, otherwise + * false. + */ + @Override + public boolean endswith(PyObject suffix, PyObject start, PyObject end) { + return unicode_endswith(suffix, start, end); } @ExposedMethod(defaults = {"null", "null"}, doc = BuiltinDocs.unicode_endswith_doc) - final boolean unicode_endswith(PyObject suffix, PyObject start, PyObject end) { - return str_endswith(suffix, start, end); + final boolean unicode_endswith(PyObject suffix, PyObject startObj, PyObject endObj) { + int[] indices = translateIndices(startObj, endObj); + String substr = getString().substring(indices[0], indices[1]); + + if (!(suffix instanceof PyTuple)) { + // It ought to be PyUnicode or some kind of bytes with the buffer API. + String s = coerceToString(suffix); + return substr.endsWith(s); + + } else { + // Loop will return true if this slice ends with any suffix in the tuple + for (PyObject suffixObj : ((PyTuple) suffix).getArray()) { + // It ought to be PyUnicode or some kind of bytes with the buffer API. + String s = coerceToString(suffixObj); + if (substr.endsWith(s)) { + return true; + } + } + // None matched + return false; + } } @ExposedMethod(doc = BuiltinDocs.unicode_translate_doc) @@ -1750,7 +2175,7 @@ final boolean unicode_isalnum() { for (Iterator iter = newSubsequenceIterator(); iter.hasNext();) { int codePoint = iter.next(); if (!(Character.isLetterOrDigit(codePoint) || // - Character.getType(codePoint) == Character.LETTER_NUMBER)) { + Character.getType(codePoint) == Character.LETTER_NUMBER)) { return false; } } @@ -1832,7 +2257,7 @@ final boolean unicode_isspace() { return false; } for (Iterator iter = newSubsequenceIterator(); iter.hasNext();) { - if (!Character.isWhitespace(iter.next())) { + if (!isPythonSpace(iter.next())) { return false; } } @@ -1933,7 +2358,7 @@ private String encodeDecimal() { int i = 0; for (Iterator iter = newSubsequenceIterator(); iter.hasNext(); i++) { int codePoint = iter.next(); - if (Character.isWhitespace(codePoint)) { + if (isPythonSpace(codePoint)) { sb.append(' '); continue; } @@ -1964,7 +2389,7 @@ private String encodeDecimalBasic() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < getString().length(); i++) { char ch = getString().charAt(i); - if (Character.isWhitespace(ch)) { + if (isPythonSpace(ch)) { sb.append(' '); continue; } diff --git a/src/org/python/core/PyUnicodeDerived.java b/src/org/python/core/PyUnicodeDerived.java index ab0acb8af..091c2126b 100644 --- a/src/org/python/core/PyUnicodeDerived.java +++ b/src/org/python/core/PyUnicodeDerived.java @@ -57,7 +57,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/core/ReflectedArgs.java b/src/org/python/core/ReflectedArgs.java index 93618e32b..f9e4712de 100644 --- a/src/org/python/core/ReflectedArgs.java +++ b/src/org/python/core/ReflectedArgs.java @@ -1,10 +1,18 @@ // Copyright (c) Corporation for National Research Initiatives +// Copyright (c)2019 Jython Developers. +// Licensed to PSF under a Contributor Agreement. package org.python.core; +import java.lang.reflect.Member; + +/** Map the signature of a method to the {@code Method} itself, within the context of a given simple name. This is used in support of signature polymorphism in Java methods and constructors reflected into Python. **/ public class ReflectedArgs { + + /** The types of arguments defining this signature (key) */ public Class[] args; - public Object data; + /** The specific method (or constructor). */ + public Member method; public Class declaringClass; @@ -20,21 +28,21 @@ public class ReflectedArgs { public static final int PyArgsKeywordsCall = 2; - public ReflectedArgs(Object data, Class[] args, Class declaringClass, boolean isStatic) { - this(data, args, declaringClass, isStatic, false); + public ReflectedArgs(Member method, Class[] args, Class declaringClass, boolean isStatic) { + this(method, args, declaringClass, isStatic, false); } - public ReflectedArgs(Object data, Class[] args, Class declaringClass, boolean isStatic, boolean isVarArgs) { - this.data = data; + public ReflectedArgs(Member method, Class[] args, Class declaringClass, boolean isStatic, + boolean isVarArgs) { + this.method = method; this.args = args; this.declaringClass = declaringClass; this.isStatic = isStatic; - this.isVarArgs = isVarArgs; // only used for varargs matching; it should be added after the unboxed form - + // only used for varargs matching; it should be added after the unboxed form + this.isVarArgs = isVarArgs; if (args.length == 1 && args[0] == PyObject[].class) { this.flags = PyArgsCall; - } else if (args.length == 2 && args[0] == PyObject[].class - && args[1] == String[].class) { + } else if (args.length == 2 && args[0] == PyObject[].class && args[1] == String[].class) { this.flags = PyArgsKeywordsCall; } else { this.flags = StandardCall; @@ -52,8 +60,8 @@ public boolean matches(PyObject self, PyObject[] pyArgs, String[] keywords, // if (isStatic ? self != null : self == null) return Py.NoConversion; /* Ugly code to handle mismatch in static vs. instance functions... */ /* - * Will be very inefficient in cases where static and instance functions - * both exist with same names and number of args + * Will be very inefficient in cases where static and instance functions both exist with + * same names and number of args */ if (this.isStatic) { if (self != null) { @@ -136,7 +144,7 @@ public boolean matches(PyObject self, PyObject[] pyArgs, String[] keywords, for (int i = 0; i < n; i++) { PyObject pyArg = pyArgs[i]; - Class targetClass = this.args[i]; + Class targetClass = this.args[i]; Object javaArg = pyArg.__tojava__(targetClass); javaArgs[i] = javaArg; if (javaArg == Py.NoConversion) { @@ -152,13 +160,12 @@ public boolean matches(PyObject self, PyObject[] pyArgs, String[] keywords, /* Boxes argument in the varargs position if not already boxed */ private PyObject[] ensureBoxedVarargs(PyObject[] pyArgs, int n) { if (pyArgs.length == 0) { - return pyArgs; + // If there are no args return an empty list + return new PyObject[] {new PyList()}; } PyObject lastArg = pyArgs[pyArgs.length - 1]; - if (lastArg instanceof PySequenceList || - lastArg instanceof PyArray || - lastArg instanceof PyXRange || - lastArg instanceof PyIterator) { + if (lastArg instanceof PySequenceList || lastArg instanceof PyArray + || lastArg instanceof PyXRange || lastArg instanceof PyIterator) { // NOTE that the check is against PySequenceList, not PySequence, // because certain Java <=> Python semantics currently require this // additional strictness. Perhaps this can be relaxed. @@ -235,9 +242,8 @@ public static int precedence(Class arg) { } /* - * Returns 0 iff arg1 == arg2 Returns +/-1 iff arg1 and arg2 are - * unimportantly different Returns +/-2 iff arg1 and arg2 are significantly - * different + * Returns 0 iff arg1 == arg2 Returns +/-1 iff arg1 and arg2 are unimportantly different Returns + * +/-2 iff arg1 and arg2 are significantly different */ public static int compare(Class arg1, Class arg2) { int p1 = precedence(arg1); @@ -319,7 +325,8 @@ public int compareTo(ReflectedArgs other) { @Override public String toString() { - String s = declaringClass + ", static=" + isStatic + ", varargs=" + isVarArgs + ",flags=" + flags + ", " + data + "\n"; + String s = declaringClass + ", static=" + isStatic + ", varargs=" + isVarArgs + ",flags=" + + flags + ", " + method + "\n"; s = s + "\t("; for (Class arg : args) { s += arg.getName() + ", "; diff --git a/src/org/python/core/RegistryKey.java b/src/org/python/core/RegistryKey.java new file mode 100644 index 000000000..39798748d --- /dev/null +++ b/src/org/python/core/RegistryKey.java @@ -0,0 +1,273 @@ +package org.python.core; + +/** + * Supported registry keys and their usage. + * + * Boolean properties are set with the String values {@code true} or {@code yes} for true, or + * {@code false} or {@code no} for false. + */ +public class RegistryKey { + + private RegistryKey() {} + + /** + * {@code python.cachedir} defines the directory to use for caches (currently just package + * information). This directory should be writable by the user. If this is an absolute path it + * is used as given, otherwise it is interpreted relative to sys.prefix (typically the directory + * of this file). + */ + public static final String PYTHON_CACHEDIR = "python.cachedir"; + + /** + * Setting {@code python.cachedir.skip} to true disables the package scan for the cachedir (as + * defined by {@code python.cachedir} or a default). Please be aware that disabling this will + * break importing from java packages. + */ + public static final String PYTHON_CACHEDIR_SKIP = "python.cachedir.skip"; + + /** + * {@code python.cpython2} is the name of a CPython executable, version 2.7. + */ + public static final String PYTHON_CPYTHON = "python.cpython2"; + + /** + * {@code python.division.warning} will print deprecation warnings when doing forced floor + * rounding with the / division operator. + *

    + * "3/2" equals 1 in Python 2.x (forced floor rounding) and 1.5 in Python 3 (convert ints to + * floats). This is equivalent to -Qwarn on the command line. See PEP 238. + *

    + * Values: {@code old}, {@code warn}, {@code warnall}. + *

    + * This property will be deprecated and removed in 3.x. + */ + public static final String PYTHON_DIVISION_WARNING = "python.division.warning"; + + /** + * {@code python.console} names the class used for the Jython console. Jython ships with a JLine + * console (http://jline.sourceforge.net/) out of the box. This is selected by default in the + * Jython command-line application ({@link org.python.util.jython}) if you do not define + * {@code python.console} to be another class on the command line. Alternatively, you can set + * {@code python.console} in the registry, but be aware that this will also affect the console + * in applications that embed a PythonInterpreter, or use Jython as a JSR-223 script engine. + * + * + * + * + * + * + * + * + *
    Values for {@code python.console}
    {@link org.python.util.JLineConsole} (default)
    {@link org.python.core.PlainConsole} (featureless)
    + *

    + * You may also set this to the name of a different console class in your classpath that extends + * PlainConsole. Note that {@code org.python.util.ReadlineConsole} has been removed in 2.7. + */ + public static final String PYTHON_CONSOLE = "python.console"; + + /** + * {@code python.console.encoding} is the encoding used reading commands from the console. Must + * be a valid Java codec name, such as cp850. + */ + public static final String PYTHON_CONSOLE_ENCODING = "python.console.encoding"; + + /** + * {@code python.import.site} controls whether to import {@code site.py}. Boolean. + *

    + * Equivalent to -S on the command line. + */ + public static final String PYTHON_IMPORT_SITE = "python.import.site"; + + /** + * When {@code python.inspect} is set, and a script given on the command line finishes, start an + * interactive interpreter. Any non-empty string value will enable this behaviour. + *

    + * Equivalent to the {@code -i} option on the command-line, or The session only actually starts + * if the console is interactive. + */ + public static final String PYTHON_INSPECT = "python.inspect"; + + /** + * {@code python.io.encoding} controls the encoding of {@code sys.stdin}, {@code sys.stdout}, + * and {@code sys.stderr}. The encoding must name a Python codec, as in {@code codecs.encode()}. + */ + public static final String PYTHON_IO_ENCODING = "python.io.encoding"; + + /** + * {@code python.io.errors} is the unicode error handler for I/O encoding problems. + */ + public static final String PYTHON_IO_ERRORS = "python.io.errors"; + + /** + * {@code python.locale.control} determines locale module behaviour, including enabling locale + * module support, currently in beta. + *

    + * Values: + * + * + * + * + * + * + * + * + * + * + *
    Values for {@code python.locale.control}
    {@code settable}Python locale module is available and supports {@code setlocale()} and other standard + * functions. This will be the default in a future Jython version.
    {@code jython2_legacy} (default)Mix of implicit Java locale and emulated 'C' locale behaviour, consistent with behaviour + * in Jython 2.7.1 and earlier. Will be deprecated in a future Jython version.
    + *

    + * More detail can be found in the documentation for the {@code locale} module and the + * underlying platform services exposed in {@link org.python.modules._locale._locale}. + */ + public static final String PYTHON_LOCALE_CONTROL = "python.locale.control"; + + /** + * {@code python.modules.builtin} controls the list of builtin modules; you can add, remove, or + * override builtin modules. The value for this registry key is a comma separated list of module + * entries, each entry of which has the following allowable forms: + *

    + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Values for {@code python.modules.builtin}
    {@code name}The module name is {@code name} and the class name is + * {@code org.python.modules.name}
    {@code name:class}The module name is {@code name} and the class name is {@code class} where class must be a + * fully qualified Java class name
    {@code name:null}The module {@code name} is removed from the list of builtin modules
    + *

    + * A good example would be to use a jni version of os for more functionality by having an entry + * such as {@code os:com.foo.jni.os} + */ + public static final String PYTHON_MODULES_BUILTIN = "python.modules.builtin"; + + /** + * If {@code python.options.caseok} is true, Jython will use the first module found on + * {@code sys.path} where java {@code File.isFile()} returns true. Setting this will have no + * effect on unix-type filesystems. On Windows/HFS+ systems setting it to true will enable + * Jython-2.0 behaviour. + */ + public static final String PYTHON_OPTIONS_CASE_OK = "python.options.caseok"; + + /** + * {@code python.options.includeJavaStackInExceptions} controls whether exceptions raised from + * Python code will include a Java stack trace in addition to the Python traceback. This can + * slow raising considerably. Boolean, true by default. + */ + public static final String PYTHON_OPTIONS_INCLUDE_JAVA_STACK_IN_EXCEPTIONS = + "python.options.includeJavaStackInExceptions"; + + /** + * When an exception occurs in Java code, and it is not caught, + * {@code python.options.showJavaExceptions} controls whether the interpreter prints out the + * Java exception in the traceback. + * + * Boolean, false by default. + */ + public static final String PYTHON_OPTIONS_SHOW_JAVA_EXCEPTIONS = + "python.options.showJavaExceptions"; + + /** + * When {@code python.options.showPythonProxyExceptions} is true, python exceptions raised in + * overridden methods will be shown on stderr. + * + */ + public static final String PYTHON_OPTIONS_SHOW_PYTHON_PROXY_EXCEPTIONS = + "python.options.showPythonProxyExceptions"; + + /** + * {@code python.options.proxyDebugDirectory} is the directory where dynamically generated + * classes are written. Nothing is ever read from here, it is only for debugging purposes. + * + */ + public static final String PYTHON_OPTIONS_PROXY_DEBUG_DIRECTORY = + "python.options.proxyDebugDirectory"; + + /** + * {@code python.options.Qnew} controls whether true division is enabled for the / operator. See + * PEP 238. Boolean. + *

    + * Equivalent to -Qnew on the command line. + */ + public static final String PYTHON_OPTIONS_Q_NEW = "python.options.Qnew"; + + /** + * {@code python.os} defines the string used to report the underlying operating system. Used as + * prefix when resolving which operating system, impacting some OS-specific behaviour. + */ + public static final String PYTHON_OS = "python.os"; + + /** + * {@code python.packages.fakepath} defines a sequence of directories and JARs that are to be + * sources of Python packages. + */ + public static final String PYTHON_PACKAGES_FAKEPATH = "python.packages.fakepath"; + + /** + * {@code python.packages.paths} defines a sequence of property names. Each property is a path + * string. The default setting causes directories and JARs on the classpath and in the JRE + * (before Java 9) to be sources of Python packages. + */ + public static final String PYTHON_PACKAGES_PATHS = "python.packages.paths"; + + /** + * {@code python.packages.directories} defines a sequence of property names. Each property name + * is a path string, in which the elements are directories. Each directory contains JAR/ZIP + * files that are to be a source of Python packages. By default, these directories are those + * where the JVM stores its optional packages as JARs (a mechanism withdrawn in Java 9). + */ + public static final String PYTHON_PACKAGES_DIRECTORIES = "python.packages.directories"; + + /** + * {@code python.path} is the search path for Python modules, equivalent to CPython's + * {@code PYTHONPATH} environment variable. + */ + public static final String PYTHON_PATH = "python.path"; + + /** + * If {@code python.security.respectJavaAccessibility} is false, and you are using a Java + * version before Java 9, then Jython can access non-public fields, methods, and constructors. + * Normally, Jython can only provide access to public members of classes. + *

    + * This may be deprecated in the future due to Java changes to accessibility from version 9 (at + * least for Oracle JDK and OpenJDK). See documentation on the {@code --illegal-access} (new) + * and {@code --permit-illegal-access} java command line flags for more detail. + *

    + * Boolean. + */ + public static final String PYTHON_SECURITY_RESPECT_JAVA_ACCESSIBILITY = + "python.security.respectJavaAccessibility"; + + /** + * {@code python.sre.cachespec} is the specification for the SRE_STATE code point cache used by + * regular expressions. The spec string is in the comma separated key=value format of + * {@code com.google.common.cache.CacheBuilder}, within guava (which is also the source of the + * cache implementation). + */ + public static final String PYTHON_SRE_CACHESPEC = "python.sre.cachespec"; + + /** + * {@code python.startup} is the name of a file to be run at the start of each interactive + * session, but not when dropping in with the -i flag in after a script has run. + */ + public static final String PYTHON_STARTUP = "python.startup"; + + /** + * {@code python.verbose} sets the verbosity level for varying degrees of informative messages. + * Valid values in order of increasing verbosity are {@code error}, {@code warning}, + * {@code message}, {@code comment}, {@code debug}. + */ + public static final String PYTHON_VERBOSE = "python.verbose"; + + /** {@code user.home} sets the user home directory. */ + public static final String USER_HOME = "user.home"; + +} diff --git a/src/org/python/core/StdoutWrapper.java b/src/org/python/core/StdoutWrapper.java index 9fde1ecc1..ef12ab6b8 100644 --- a/src/org/python/core/StdoutWrapper.java +++ b/src/org/python/core/StdoutWrapper.java @@ -102,28 +102,33 @@ public void flushLine() { } private String printToFile(PyFile file, PyObject o) { - String s; + // We must ensure o is a byte string before we write it to the stream + String bytes; + if (!(o instanceof PyUnicode)) { + o = o.__str__(); + } + // o is now a PyString, but it might be unicode or bytes if (o instanceof PyUnicode) { // Use the encoding and policy defined for the stream. (Each may be null.) - s = ((PyUnicode)o).encode(file.encoding, file.errors); + bytes = ((PyUnicode)o).encode(file.encoding, file.errors); } else { - s = o.__str__().toString(); + bytes = ((PyString)o).getString(); } - file.write(s); - return s; + file.write(bytes); + return bytes; } private String printToFileWriter(PyFileWriter file, PyObject o) { - // since we are outputting directly to a character stream, - // avoid doing an encoding - String s; - if (o instanceof PyString) { - s = ((PyString) o).getString(); + // since we are outputting directly to a character stream, avoid encoding + String chars; + if (o instanceof PyUnicode) { + chars = ((PyString) o).getString(); } else { - s = o.__str__().toString(); + // Bytes here are assumed to be code points, as in PyFileWriter.write() + chars = o.__str__().getString(); } - file.write(s); - return s; + file.write(chars); + return chars; } private void printToFileObject(PyObject file, PyObject o) { @@ -248,11 +253,11 @@ public void print(PyObject o, boolean space, boolean newline) { } public void print(String s) { - print(Py.newStringOrUnicode(s), false, false); + print(Py.newUnicode(s), false, false); } public void println(String s) { - print(Py.newStringOrUnicode(s), false, true); + print(Py.newUnicode(s), false, true); } public void print(PyObject o) { diff --git a/src/org/python/core/SyspathArchive.java b/src/org/python/core/SyspathArchive.java index 2fadabe8a..eb4cee493 100644 --- a/src/org/python/core/SyspathArchive.java +++ b/src/org/python/core/SyspathArchive.java @@ -1,6 +1,6 @@ - package org.python.core; import java.io.*; +import java.util.logging.Logger; import java.util.zip.*; @Untraversable @@ -8,7 +8,8 @@ public class SyspathArchive extends PyString { private ZipFile zipFile; public SyspathArchive(String archiveName) throws IOException { - super(archiveName); + // As a string-like object (on sys.path) an FS-encoded bytes object is expected + super(Py.fileSystemEncode(archiveName).getString()); archiveName = getArchiveName(archiveName); if(archiveName == null) { throw new IOException("path '" + archiveName + "' not an archive"); @@ -20,7 +21,8 @@ public SyspathArchive(String archiveName) throws IOException { } SyspathArchive(ZipFile zipFile, String archiveName) { - super(archiveName); + // As a string-like object (on sys.path) an FS-encoded bytes object is expected + super(Py.fileSystemEncode(archiveName).getString()); this.zipFile = zipFile; } @@ -86,8 +88,9 @@ InputStream getInputStream(ZipEntry entry) throws IOException { int off = 0; while (len > 0) { int l = istream.read(buffer, off, buffer.length - off); - if (l < 0) + if (l < 0) { return null; + } off += l; len -= l; } @@ -96,12 +99,13 @@ InputStream getInputStream(ZipEntry entry) throws IOException { } /* + private static Logger logger = Logger.getLogger("org.python.import"); protected void finalize() { System.out.println("closing zip file " + toString()); try { zipFile.close(); } catch (IOException e) { - Py.writeDebug("import", "closing zipEntry failed"); + logger.log(Level.FINE, "closing zipEntry failed"); } } */ diff --git a/src/org/python/core/SyspathJavaLoader.java b/src/org/python/core/SyspathJavaLoader.java index 74485fff1..65ba75738 100644 --- a/src/org/python/core/SyspathJavaLoader.java +++ b/src/org/python/core/SyspathJavaLoader.java @@ -26,20 +26,20 @@ public class SyspathJavaLoader extends ClassLoader { public SyspathJavaLoader(ClassLoader parent) { super(parent); } - - /** + + /** * Returns a byte[] with the contents read from an InputStream. - * + * * The stream is closed after reading the bytes. - * - * @param input The input stream + * + * @param input The input stream * @param size The number of bytes to read - * + * * @return an array of byte[size] with the contents read * */ private byte[] getBytesFromInputStream(InputStream input, int size) { - try { + try { byte[] buffer = new byte[size]; int nread = 0; while(nread < size) { @@ -56,9 +56,9 @@ private byte[] getBytesFromInputStream(InputStream input, int size) { } } } - + private byte[] getBytesFromDir(String dir, String name) { - try { + try { File file = getFile(dir, name); if (file == null) { return null; @@ -71,7 +71,7 @@ private byte[] getBytesFromDir(String dir, String name) { } } - + private byte[] getBytesFromArchive(SyspathArchive archive, String name) { String entryname = name.replace('.', SLASH_CHAR) + ".class"; ZipEntry ze = archive.getEntry(entryname); @@ -79,7 +79,7 @@ private byte[] getBytesFromArchive(SyspathArchive archive, String name) { return null; } try { - return getBytesFromInputStream(archive.getInputStream(ze), + return getBytesFromInputStream(archive.getInputStream(ze), (int)ze.getSize()); } catch (IOException e) { return null; @@ -98,11 +98,11 @@ protected Package definePackageForClass(String name) { } return pkg; } - + @Override protected Class findClass(String name) throws ClassNotFoundException { PySystemState sys = Py.getSystemState(); - ClassLoader sysClassLoader = sys.getClassLoader(); + ClassLoader sysClassLoader = sys.getClassLoader(); if (sysClassLoader != null) { // sys.classLoader overrides this class loader! return sysClassLoader.loadClass(name); @@ -113,14 +113,11 @@ protected Class findClass(String name) throws ClassNotFoundException { byte[] buffer; PyObject entry = replacePathItem(sys, i, path); if (entry instanceof SyspathArchive) { - SyspathArchive archive = (SyspathArchive)entry; - buffer = getBytesFromArchive(archive, name); + SyspathArchive archive = (SyspathArchive) entry; + buffer = getBytesFromArchive(archive, name); } else { - if (!(entry instanceof PyUnicode)) { - entry = entry.__str__(); - } - String dir = entry.toString(); - buffer = getBytesFromDir(dir, name); + String dir = imp.fileSystemDecode(entry, false); + buffer = dir != null ? getBytesFromDir(dir, name) : null; } if (buffer != null) { definePackageForClass(name); @@ -130,7 +127,7 @@ protected Class findClass(String name) throws ClassNotFoundException { // couldn't find the .class file on sys.path throw new ClassNotFoundException(name); } - + @Override protected URL findResource(String res) { PySystemState sys = Py.getSystemState(); @@ -157,10 +154,7 @@ protected URL findResource(String res) { } continue; } - if (!(entry instanceof PyUnicode)) { - entry = entry.__str__(); - } - String dir = sys.getPath(entry.toString()); + String dir = sys.getPath(Py.fileSystemDecode(entry)); try { File resource = new File(dir, res); if (!resource.exists()) { @@ -179,7 +173,7 @@ protected Enumeration findResources(String res) throws IOException { List resources = new ArrayList(); - + PySystemState sys = Py.getSystemState(); res = deslashResource(res); @@ -204,10 +198,7 @@ protected Enumeration findResources(String res) } continue; } - if (!(entry instanceof PyUnicode)) { - entry = entry.__str__(); - } - String dir = sys.getPath(entry.toString()); + String dir = sys.getPath(Py.fileSystemDecode(entry)); try { File resource = new File(dir, res); if (!resource.exists()) { @@ -220,7 +211,7 @@ protected Enumeration findResources(String res) } return Collections.enumeration(resources); } - + static PyObject replacePathItem(PySystemState sys, int idx, PyList paths) { PyObject path = paths.__getitem__(idx); if (path instanceof SyspathArchive) { @@ -229,9 +220,9 @@ static PyObject replacePathItem(PySystemState sys, int idx, PyList paths) { } try { - // this has the side affect of adding the jar to the PackageManager during the + // this has the side effect of adding the jar to the PackageManager during the // initialization of the SyspathArchive - path = new SyspathArchive(sys.getPath(path.toString())); + path = new SyspathArchive(sys.getPath(Py.fileSystemDecode(path))); } catch (Exception e) { return path; } diff --git a/src/org/python/core/ThreadState.java b/src/org/python/core/ThreadState.java index 29c9d295d..60c83626f 100644 --- a/src/org/python/core/ThreadState.java +++ b/src/org/python/core/ThreadState.java @@ -38,19 +38,19 @@ public void setSystemState(PySystemState systemState) { systemStateRef = new PySystemStateRef(systemState, this); } } - + public PySystemState getSystemState() { PySystemState systemState = systemStateRef == null ? null : systemStateRef.get(); - return systemState == null ? Py.defaultSystemState : systemState; + return systemState == null ? Py.defaultSystemState : systemState; } - + public boolean enterRepr(PyObject obj) { if (reprStack == null) { reprStack = new PyList(new PyObject[] {obj}); return true; } for (int i = reprStack.size() - 1; i >= 0; i--) { - if (obj == reprStack.pyget(i)) { + if (obj._is(reprStack.pyget(i)).__nonzero__()) { return false; } } @@ -63,7 +63,7 @@ public void exitRepr(PyObject obj) { return; } for (int i = reprStack.size() - 1; i >= 0; i--) { - if (reprStack.pyget(i) == obj) { + if (obj._is(reprStack.pyget(i)).__nonzero__()) { reprStack.delRange(i, reprStack.size()); } } diff --git a/src/org/python/core/ThreadStateMapping.java b/src/org/python/core/ThreadStateMapping.java index 61bf03532..737ed7906 100644 --- a/src/org/python/core/ThreadStateMapping.java +++ b/src/org/python/core/ThreadStateMapping.java @@ -88,4 +88,25 @@ public static void exitCall(ThreadState ts) { scoped[1] = null; // allow corresponding PySystemState to be GCed } } + + @SuppressWarnings("unchecked") + private static Map.Entry[] entriesPrototype = new Map.Entry[0]; + public static PyDictionary _current_frames() { + Map.Entry[] entries = globalThreadStates.entrySet().toArray(entriesPrototype); + int i = 0; + for (Map.Entry entry: entries) { + if (entry.getValue().frame != null) { + ++i; + } + } + PyObject elements[] = new PyObject[i*2]; + i = 0; + for (Map.Entry entry: entries) { + if (entry.getValue().frame != null) { + elements[i++] = Py.newInteger(entry.getKey().getId()); + elements[i++] = entry.getValue().frame; + } + } + return new PyDictionary(elements); + } } diff --git a/src/org/python/core/Traverseproc.java b/src/org/python/core/Traverseproc.java index 81c57e820..36173bc71 100644 --- a/src/org/python/core/Traverseproc.java +++ b/src/org/python/core/Traverseproc.java @@ -45,7 +45,7 @@ *

    *

    * Note that the slots-array and - if existent - the user-dict of {@code fooDerived} - * classes is traversed by {@link org.python.core.TraverseProcDerived}. + * classes is traversed by {@link org.python.core.TraverseprocDerived}. * The gc-module takes care of exploiting both traverse methods in its static traverse * method. So for manual traversion one should always use * {@link org.python.modules.gc#traverse(PyObject, Visitproc, Object)} rather @@ -147,7 +147,7 @@ *

      *  {@literal @}Override
      *  public boolean refersDirectlyTo(PyObject ob) {
    - *      return ob != null && (ob == im_class || ob == __func__ || ob == __self__);
    + *      return ob != null {@literal &&} (ob == im_class || ob == __func__ || ob == __self__);
      *  }
      * 
    * If there is a Java-set or other iterable that it is not a {@code PyObject}, @@ -177,7 +177,7 @@ *
      *  {@literal @}Override
      *  public boolean refersDirectlyTo(PyObject ob) {
    - *      return ob != null && _set.contains(ob);
    + *      return ob != null {@literal &&} _set.contains(ob);
      *  }
      * 
    * If a class extends a {@code Traverseproc}-implementing class and adds @@ -256,7 +256,6 @@ * throw new UnsupportedOperationException(); * } * - *

    *

    *
    * List of {@code PyObject}-subclasses

    @@ -469,7 +468,7 @@ * EncodeBasestringAsciiFunction - no refs, untraversable
    *
    * org.python.modules._jythonlib:
    - * dict_builder - Traverseproc
    + * dict_builder - Traverseproc
    *
    * org.python.modules._threading:
    * Condition - Traverseproc
    @@ -653,7 +652,7 @@ public interface Traverseproc { * If {@link Visitproc#visit(PyObject, Object)} returns * nonzero, this return value * must be returned immediately by traverse. - * + * * {@link Visitproc#visit(PyObject, Object)} must not be * called with a {@code null} PyObject-argument. */ diff --git a/src/org/python/core/TraverseprocDerived.java b/src/org/python/core/TraverseprocDerived.java index da0b13861..ad8d12aa7 100644 --- a/src/org/python/core/TraverseprocDerived.java +++ b/src/org/python/core/TraverseprocDerived.java @@ -5,7 +5,7 @@ * but traverses only the {@code slots[]}-array of * {@code fooDerived}-classes. This way we avoid that the traverse * method of a traversable {@link org.python.core.PyObject} is - * overwritten by the derived version. + * overridden by the derived version. * {@link org.python.modules.gc#traverse(PyObject, Visitproc, Object)} takes care of * exploiting both traverse methods. */ diff --git a/src/org/python/core/__builtin__.java b/src/org/python/core/__builtin__.java index cdd2c726a..330206fa9 100644 --- a/src/org/python/core/__builtin__.java +++ b/src/org/python/core/__builtin__.java @@ -85,7 +85,7 @@ public PyObject __call__(PyObject arg1) { case 18: return __builtin__.eval(arg1); case 19: - __builtin__.execfile(arg1.asString()); + __builtin__.execfile(Py.fileSystemDecode(arg1)); return Py.None; case 23: return __builtin__.hex(arg1); @@ -141,7 +141,7 @@ public PyObject __call__(PyObject arg1, PyObject arg2) { case 18: return __builtin__.eval(arg1, arg2); case 19: - __builtin__.execfile(arg1.asString(), arg2); + __builtin__.execfile(Py.fileSystemDecode(arg1), arg2); return Py.None; case 20: return __builtin__.filter(arg1, arg2); @@ -191,7 +191,7 @@ public PyObject __call__(PyObject arg1, PyObject arg2, PyObject arg3) { case 18: return __builtin__.eval(arg1, arg2, arg3); case 19: - __builtin__.execfile(arg1.asString(), arg2, arg3); + __builtin__.execfile(Py.fileSystemDecode(arg1), arg2, arg3); return Py.None; case 21: return __builtin__.getattr(arg1, arg2, arg3); @@ -785,7 +785,7 @@ public static PyString oct(PyObject o) { * * @param c string-like object of length 1 * @return ordinal value of character or byte value in - * @throws PyException (TypeError) if not a string-like type + * @throws PyException {@code TypeError} if not a string-like type */ public static final int ord(PyObject c) throws PyException { final int length; @@ -1267,17 +1267,22 @@ class ImportFunction extends PyBuiltinFunction { "is the number of parent directories to search relative to the current module."); } + private static final String[] ARGS = {"name", "globals", "locals", "fromlist", "level"}; + @Override public PyObject __call__(PyObject args[], String keywords[]) { - ArgParser ap = new ArgParser("__import__", args, keywords, - new String[] {"name", "globals", "locals", "fromlist", - "level"}, - 1); - String module = ap.getString(0); + ArgParser ap = new ArgParser("__import__", args, keywords, ARGS, 1); + PyObject module = ap.getPyObject(0); + String name; + if (module instanceof PyUnicode) { + name = ((PyUnicode) module).encode("ascii").toString(); + } else { + name = ap.getString(0); + } PyObject globals = ap.getPyObject(1, null); PyObject fromlist = ap.getPyObject(3, Py.EmptyTuple); int level = ap.getInt(4, imp.DEFAULT_LEVEL); - return imp.importName(module.intern(), fromlist == Py.None || fromlist.__len__() == 0, + return imp.importName(name.intern(), fromlist == Py.None || fromlist.__len__() == 0, globals, fromlist, level); } } @@ -1629,7 +1634,7 @@ public PyObject __call__(PyObject args[], String kwds[]) { "dont_inherit"}, 3); PyObject source = ap.getPyObject(0); - String filename = ap.getString(1); + String filename = Py.fileSystemDecode(ap.getPyObject(1)); String mode = ap.getString(2); int flags = ap.getInt(3, 0); boolean dont_inherit = ap.getPyObject(4, Py.False).__nonzero__(); diff --git a/src/org/python/core/buffer/BaseArrayBuffer.java b/src/org/python/core/buffer/BaseArrayBuffer.java index f869c9766..cc24351ff 100644 --- a/src/org/python/core/buffer/BaseArrayBuffer.java +++ b/src/org/python/core/buffer/BaseArrayBuffer.java @@ -126,7 +126,7 @@ public void copyFrom(byte[] src, int srcPos, int destIndex, int count) * @param destIndex starting item-index in the destination (i.e. this) * @param count number of items to copy in * @throws IndexOutOfBoundsException if access out of bounds in source or destination - * @throws PyException (TypeError) if read-only buffer + * @throws PyException {@code TypeError} if read-only buffer */ protected void copyFrom(byte[] src, int srcPos, int srcStride, int destIndex, int count) throws IndexOutOfBoundsException, PyException { diff --git a/src/org/python/core/buffer/BaseBuffer.java b/src/org/python/core/buffer/BaseBuffer.java index 50948103e..ba2c31b9b 100644 --- a/src/org/python/core/buffer/BaseBuffer.java +++ b/src/org/python/core/buffer/BaseBuffer.java @@ -22,12 +22,12 @@ * {@link #getNIOByteBufferImpl()} for ByteBuffers that wrap the storage, and a factory * for slices {@link #getBufferSlice(int, int, int, int)}. *

    - * The sub-class constructor must specify the feature flags (see {@link #BaseBuffer(int)}), set - * {@link #index0}, {@link #shape} and {@link #strides}, and finally check the client capabilities - * with {@link #checkRequestFlags(int)}. Sub-classes intended to represent slices of exporters that - * must count their exports as part of a locking protocol, as does bytearray, must - * override {@link #getRoot()} so that a buffer view {@link #release()} on a slice, propagates to - * the buffer view that provided it. + * The sub-class constructor must specify the feature flags (see + * {@link #BaseBuffer(int, int, int[], int[])}), set {@link #index0}, {@link #shape} and + * {@link #strides}, and finally check the client capabilities with {@link #checkRequestFlags(int)}. + * A sub-class intended to represent slices of an exporter that counts its exports, as part of a + * locking protocol like bytearray's, must override {@link #getRoot()} so that a call + * to {@link #release()} on a view of slice, propagates to the buffer view that provided the slice. *

    * Access methods provided here necessarily work with the abstracted {@link #byteAtImpl(int)}, * {@link #storeAtImpl(byte, int)} interface, but subclasses are able to override them with more @@ -182,7 +182,7 @@ protected final void addFeatureFlags(int flags) { /** * Remove features from this buffer expressed using the constants defined in {@link PyBUF}, * clearing individual flags specified while leaving others already set. Equivalent to - * setFeatureFlags(~flags & getFeatureFlags()). + * {@code setFeatureFlags(~flags & getFeatureFlags())}. * * @param flags to clear within the feature flags */ @@ -211,7 +211,7 @@ protected final void removeFeatureFlags(int flags) { * corresponding to an array that the buffer deems necessary. * * @param flags capabilities of and navigation assumed by the consumer - * @throws PyException (BufferError) when expectations do not correspond with the buffer + * @throws PyException {@code BufferError} when expectations do not correspond with the buffer */ protected void checkRequestFlags(int flags) throws PyException { /* @@ -291,7 +291,7 @@ public final BufferProtocol getObj() { * * @param value to store * @param byteIndex byte-index of location to retrieve - * @throws PyException(BufferError) if this object is read-only. + * @throws PyException {@code BufferError} if this object is read-only. */ abstract protected void storeAtImpl(byte value, int byteIndex) throws IndexOutOfBoundsException, PyException; @@ -820,7 +820,7 @@ public String toString() { * * @param indices into the buffer (to test) * @return number of dimensions - * @throws PyException (BufferError) if wrong number of indices + * @throws PyException {@code BufferError} if wrong number of indices */ int checkDimension(int[] indices) throws PyException { int n = indices.length; @@ -834,7 +834,7 @@ int checkDimension(int[] indices) throws PyException { * N-dimensional arrays. * * @param n number of dimensions being assumed by caller - * @throws PyException (BufferError) if wrong number of indices + * @throws PyException {@code BufferError} if wrong number of indices */ void checkDimension(int n) throws PyException { int ndim = getNdim(); @@ -848,7 +848,7 @@ void checkDimension(int n) throws PyException { /** * Check that the buffer is writable. * - * @throws PyException (TypeError) if not + * @throws PyException {@code TypeError} if not */ protected void checkWritable() throws PyException { if (isReadonly()) { @@ -859,7 +859,7 @@ protected void checkWritable() throws PyException { /** * Check that the buffer is backed by an array the client can access as byte[]. * - * @throws PyException (BufferError) if not + * @throws PyException {@code BufferError} if not */ protected void checkHasArray() throws PyException { if (!hasArray()) { diff --git a/src/org/python/core/buffer/BaseNIOBuffer.java b/src/org/python/core/buffer/BaseNIOBuffer.java index 088bf8661..fea4a8c92 100644 --- a/src/org/python/core/buffer/BaseNIOBuffer.java +++ b/src/org/python/core/buffer/BaseNIOBuffer.java @@ -182,7 +182,7 @@ public void copyFrom(byte[] src, int srcPos, int destIndex, int count) * @param destIndex starting item-index in the destination (i.e. this) * @param count number of items to copy in * @throws IndexOutOfBoundsException if access out of bounds in source or destination - * @throws PyException (TypeError) if read-only buffer + * @throws PyException {@code TypeError} if read-only buffer */ // XXX Should this become part of the PyBUffer interface? protected void copyFrom(ByteBuffer src, int destIndex, int count) diff --git a/src/org/python/core/buffer/SimpleBuffer.java b/src/org/python/core/buffer/SimpleBuffer.java index c2ea9d654..57582241e 100644 --- a/src/org/python/core/buffer/SimpleBuffer.java +++ b/src/org/python/core/buffer/SimpleBuffer.java @@ -48,7 +48,7 @@ protected SimpleBuffer(BufferProtocol obj, byte[] storage, int index0, int size) * @throws NullPointerException if storage is null * @throws ArrayIndexOutOfBoundsException if index0 and size are * inconsistent with storage.length - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleBuffer(int flags, BufferProtocol obj, byte[] storage, int index0, int size) throws PyException, ArrayIndexOutOfBoundsException, NullPointerException { @@ -83,7 +83,7 @@ protected SimpleBuffer(BufferProtocol obj, byte[] storage) throws NullPointerExc * @param obj exporting object (or null) * @param storage the array of bytes storing the implementation of the exporting object * @throws NullPointerException if storage is null - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleBuffer(int flags, BufferProtocol obj, byte[] storage) throws PyException, NullPointerException { diff --git a/src/org/python/core/buffer/SimpleNIOBuffer.java b/src/org/python/core/buffer/SimpleNIOBuffer.java index 0bdf51954..d6ff3537d 100644 --- a/src/org/python/core/buffer/SimpleNIOBuffer.java +++ b/src/org/python/core/buffer/SimpleNIOBuffer.java @@ -58,7 +58,7 @@ protected SimpleNIOBuffer(BufferProtocol obj, ByteBuffer storage, int index0, in * @throws NullPointerException if storage is null * @throws ArrayIndexOutOfBoundsException if index0 and size are * inconsistent with storage.length - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleNIOBuffer(int flags, BufferProtocol obj, ByteBuffer storage, int index0, int size) throws PyException, ArrayIndexOutOfBoundsException, NullPointerException { @@ -92,7 +92,7 @@ protected SimpleNIOBuffer(BufferProtocol obj, ByteBuffer storage) throws NullPoi * @param obj exporting object (or null) * @param storage the ByteBuffer wrapping the exported object state * @throws NullPointerException if storage is null - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleNIOBuffer(int flags, BufferProtocol obj, ByteBuffer storage) throws PyException, NullPointerException { diff --git a/src/org/python/core/buffer/SimpleStringBuffer.java b/src/org/python/core/buffer/SimpleStringBuffer.java index 0c7379782..0533c4b2a 100644 --- a/src/org/python/core/buffer/SimpleStringBuffer.java +++ b/src/org/python/core/buffer/SimpleStringBuffer.java @@ -10,7 +10,7 @@ * Buffer API that appears to be a one-dimensional array of one-byte items providing read-only API, * but which is actually backed by a Java String. Some of the buffer API absolutely needs access to * the data as a byte array (those parts that involve a {@link java.nio.ByteBuffer} or - * {@link PyBuffer.Pointer} result), and therefore this class must create a byte array from the + * {@link org.python.core.PyBuffer.Pointer} result), and therefore this class must create a byte array from the * String for them. However, it defers creation of a byte array until that part of the API is * actually used. Where possible, this class overrides those methods in SimpleBuffer that would * otherwise access the byte array attribute to use the String instead. diff --git a/src/org/python/core/buffer/SimpleWritableBuffer.java b/src/org/python/core/buffer/SimpleWritableBuffer.java index 0d23780c4..e2c785b07 100644 --- a/src/org/python/core/buffer/SimpleWritableBuffer.java +++ b/src/org/python/core/buffer/SimpleWritableBuffer.java @@ -19,7 +19,7 @@ public class SimpleWritableBuffer extends SimpleBuffer { * @param storage the array of bytes storing the implementation of the exporting object * @param index0 offset where the data starts in that array (item[0]) * @param size the number of bytes occupied - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleWritableBuffer(int flags, BufferProtocol obj, byte[] storage, int index0, int size) throws PyException, NullPointerException { @@ -36,7 +36,7 @@ public SimpleWritableBuffer(int flags, BufferProtocol obj, byte[] storage, int i * @param flags consumer requirements * @param obj exporting object (or null) * @param storage the array of bytes storing the implementation of the exporting object - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SimpleWritableBuffer(int flags, BufferProtocol obj, byte[] storage) throws PyException, NullPointerException { diff --git a/src/org/python/core/buffer/Strided1DBuffer.java b/src/org/python/core/buffer/Strided1DBuffer.java index cfbbe186a..116ce0114 100644 --- a/src/org/python/core/buffer/Strided1DBuffer.java +++ b/src/org/python/core/buffer/Strided1DBuffer.java @@ -46,8 +46,7 @@ public class Strided1DBuffer extends BaseArrayBuffer { *

    * The sub-class constructor should check that the intended access is compatible with this * object by calling {@link #checkRequestFlags(int)}. (See the source of - * {@link Strided1DWritableBuffer#Strided1DWritableBuffer(int, byte[], int, int, int)} for an - * example of this use.) + * {@link Strided1DWritableBuffer} for an example of this use.) * * @param obj exporting object (or null) * @param storage raw byte array containing exported data @@ -118,7 +117,7 @@ protected Strided1DBuffer(BufferProtocol obj, byte[] storage, int index0, int co * @throws NullPointerException if storage is null * @throws ArrayIndexOutOfBoundsException if index0, count and * stride are inconsistent with storage.length - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public Strided1DBuffer(int flags, BufferProtocol obj, byte[] storage, int index0, int count, int stride) throws ArrayIndexOutOfBoundsException, NullPointerException, PyException { @@ -198,7 +197,7 @@ static class SlicedView extends Strided1DBuffer { * @param index0 index into storage of item[0] * @param count number of items in the sliced view * @param stride in between successive elements of the new PyBuffer - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int count, int stride) throws PyException { diff --git a/src/org/python/core/buffer/Strided1DNIOBuffer.java b/src/org/python/core/buffer/Strided1DNIOBuffer.java index cd60ee661..0b519f89b 100644 --- a/src/org/python/core/buffer/Strided1DNIOBuffer.java +++ b/src/org/python/core/buffer/Strided1DNIOBuffer.java @@ -48,8 +48,7 @@ public class Strided1DNIOBuffer extends BaseNIOBuffer { *

    * The sub-class constructor should check that the intended access is compatible with this * object by calling {@link #checkRequestFlags(int)}. (See the source of - * {@link Strided1DWritableBuffer#Strided1DWritableBuffer(int, ByteBuffer, int, int, int)} for - * an example of this use.) + * {@link Strided1DWritableBuffer} for an example of this use.) * * @param obj exporting object (or null) * @param storage the ByteBuffer wrapping the exported object state. NOTE: this @@ -132,7 +131,7 @@ protected Strided1DNIOBuffer(BufferProtocol obj, ByteBuffer storage, int index0, * @throws NullPointerException if storage is null * @throws ArrayIndexOutOfBoundsException if index0, count and * stride are inconsistent with storage.length - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public Strided1DNIOBuffer(int flags, BufferProtocol obj, ByteBuffer storage, int index0, int count, int stride) throws ArrayIndexOutOfBoundsException, NullPointerException, @@ -191,7 +190,7 @@ static class SlicedView extends Strided1DNIOBuffer { * @param index0 index into storage of item[0] * @param count the number of items in the sliced view * @param stride in between successive elements of the new PyBuffer - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SlicedView(PyBuffer root, int flags, ByteBuffer storage, int index0, int count, int stride) throws PyException { diff --git a/src/org/python/core/buffer/Strided1DWritableBuffer.java b/src/org/python/core/buffer/Strided1DWritableBuffer.java index 78d656482..9aa9ad389 100644 --- a/src/org/python/core/buffer/Strided1DWritableBuffer.java +++ b/src/org/python/core/buffer/Strided1DWritableBuffer.java @@ -15,7 +15,7 @@ public class Strided1DWritableBuffer extends Strided1DBuffer { * Provide an instance of Strided1DWritableBuffer on a particular array of bytes * specifying a starting index, the number of items in the result, and a byte-indexing stride. * The result of byteAt(i) will be equal to storage[index0+stride*i] - * (whatever the sign of stride>0), valid for 0<=i<count. + * (whatever the sign of {@code stride}), valid for 0≤{@code i}<{@code count}. *

    * The constructed PyBuffer meets the consumer's expectations as expressed in the * flags argument, or an exception will be thrown if these are incompatible with @@ -34,7 +34,7 @@ public class Strided1DWritableBuffer extends Strided1DBuffer { * @throws NullPointerException if storage is null * @throws ArrayIndexOutOfBoundsException if index0, count and * stride are inconsistent with storage.length - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public Strided1DWritableBuffer(int flags, BufferProtocol obj, byte[] storage, int index0, int count, int stride) throws ArrayIndexOutOfBoundsException, NullPointerException, @@ -105,7 +105,7 @@ static class SlicedView extends Strided1DWritableBuffer { * @param index0 index into storage of item[0] * @param count number of items in the sliced view * @param stride in between successive elements of the new PyBuffer - * @throws PyException (BufferError) when expectations do not correspond with the type + * @throws PyException {@code BufferError} when expectations do not correspond with the type */ public SlicedView(PyBuffer root, int flags, byte[] storage, int index0, int count, int stride) throws PyException { diff --git a/src/org/python/core/buffer/ZeroByteBuffer.java b/src/org/python/core/buffer/ZeroByteBuffer.java index c64456095..3743a83b1 100644 --- a/src/org/python/core/buffer/ZeroByteBuffer.java +++ b/src/org/python/core/buffer/ZeroByteBuffer.java @@ -29,7 +29,8 @@ public class ZeroByteBuffer extends BaseArrayBuffer { * @param obj exporting object (or null) * @param readonly set true if not to be considered writable * @param hasArray set true if to be considered as backed by an array - * @throws PyException (BufferError) when client expectations do not correspond with the type + * @throws PyException {@code BufferError} when client expectations do not correspond with the + * type */ public ZeroByteBuffer(int flags, BufferProtocol obj, boolean readonly, boolean hasArray) throws PyException { diff --git a/src/org/python/core/codecs.java b/src/org/python/core/codecs.java index 8f796f6f9..3ca1ed354 100644 --- a/src/org/python/core/codecs.java +++ b/src/org/python/core/codecs.java @@ -63,15 +63,13 @@ private static String normalizestring(String string) { } /** - * Decode the bytes v using the codec registered for the encoding. - * The encoding defaults to the system default encoding - * (see {@link codecs#getDefaultEncoding()}). - * The string errors may name a different error handling - * policy (built-in or registered with {@link #register_error(String, PyObject)}). - * The default error policy is 'strict' meaning that encoding errors raise a - * ValueError. - * This method is exposed through the _codecs module as - * {@link _codecs#decode(PyString, String, String)}. + * Decode the bytes v using the codec registered for the encoding. The + * encoding defaults to the system default encoding (see + * {@link codecs#getDefaultEncoding()}). The string errors may name a different + * error handling policy (built-in or registered with + * {@link #register_error(String, PyObject)}). The default error policy is 'strict' meaning that + * encoding errors raise a ValueError. This method is exposed through the _codecs + * module as {@link _codecs#decode(PyString, PyString, PyString)} * * @param v bytes to be decoded * @param encoding name of encoding (to look up in codec registry) @@ -126,7 +124,7 @@ public static PyObject decode(PyString v, String encoding, String errors) { } private static PyUnicode wrapDecodeResult(String result) { - return new PyUnicode(result, true); + return new PyUnicode(result); } /** @@ -400,15 +398,15 @@ private static void backslashreplace_internal(int start, int end, String object, };//@formatter:on /** - * Determine whether this character should be encoded as itself. The answer depends on whether - * we are encoding set O (optional special characters) as itself, and also on whether we are - * encoding whitespace as itself. RFC2152 makes it clear that the answers to these questions - * vary between applications, so this code needs to be flexible. + * Determine whether, in the UTF-7 encoder, this character should be encoded as itself. The + * answer depends on whether we are encoding set O (optional special characters) as itself, and + * also on whether we are encoding whitespace as itself. RFC2152 makes it clear that the answers + * to these questions vary between applications, so this code needs to be flexible. * * @param c code point of the character * @param directO true if characters in "set O" may be encoded as themselves * @param directWS true if whitespace characters may be encoded as themselves - * @return + * @return {@code true} if {@code c} should be encoded as itself */ private static boolean ENCODE_DIRECT(int c, boolean directO, boolean directWS) { @@ -418,7 +416,7 @@ private static boolean ENCODE_DIRECT(int c, boolean directO, boolean directWS) { switch (utf7_category[c]) { case 0: // This is a regular character return true; - case 1: // This is a whilespace character + case 1: // This is a white space character return directWS; case 2: // This is an optional special character return directO; @@ -725,6 +723,7 @@ private static int emitCodePoints(StringBuilder v, long buffer, int n) { * decoder, where partial output characters are an error. For 32 bits or more, It duplicates * some logic, but is called only during abnormal processing. The return is: * + * * * * @@ -870,7 +869,7 @@ public static String PyUnicode_EncodeUTF7(String unicode, boolean base64SetO, // Currently we are in Base64 encoding: should we switch out? if (ENCODE_DIRECT(ch, !base64SetO, !base64WhiteSpace)) { /* - * The next character is one for which we do not neeed to be in Base64, so pad + * The next character is one for which we do not need to be in Base64, so pad * out to 6n the Base64 bits we currently have buffered and emit them. Then * switch to US-ASCII. */ @@ -891,7 +890,7 @@ public static String PyUnicode_EncodeUTF7(String unicode, boolean base64SetO, ch = '-'; // Comes out as +- } else if (!ENCODE_DIRECT(ch, !base64SetO, !base64WhiteSpace)) { /* - * The next character is one for which we neeed to be in Base64, so switch to it + * The next character is one for which we need to be in Base64, so switch to it * and emit the Base64 start marker and initialise the coder. */ v.append('+'); diff --git a/src/org/python/core/exceptions.java b/src/org/python/core/exceptions.java index 4f79ff12d..b02e27254 100644 --- a/src/org/python/core/exceptions.java +++ b/src/org/python/core/exceptions.java @@ -4,6 +4,7 @@ import java.io.File; import java.lang.reflect.Method; +import org.python.modules._locale._locale; import org.python.modules.zipimport.zipimport; /** @@ -174,13 +175,17 @@ public static void classDictInit(PyObject dict) { "Base class for warnings about bytes and buffer related problems, mostly\n" + "related to conversion from str or comparing to str."); - // Initialize ZipImportError here, where it's safe to; it's - // needed immediately - zipimport.initClassExceptions(dict); - + buildModuleExceptions(dict); ts.frame = ts.frame.f_back; } + // Native modules exposing errors as part of their public interface + private static void buildModuleExceptions(PyObject dict) { + // Initialize ZipImportError here, where it's safe to; it's needed immediately + zipimport.initClassExceptions(dict); + _locale.initClassExceptions(dict); + } + public static PyObject SyntaxError() { PyObject __dict__ = new PyStringMap(); defineSlots(__dict__, "msg", "filename", "lineno", "offset", "text", diff --git a/src/org/python/core/finalization/FinalizableBuiltin.java b/src/org/python/core/finalization/FinalizableBuiltin.java index 476e66233..eddb15107 100644 --- a/src/org/python/core/finalization/FinalizableBuiltin.java +++ b/src/org/python/core/finalization/FinalizableBuiltin.java @@ -12,7 +12,7 @@ public interface FinalizableBuiltin { * A FinalizeTrigger calls {@link FinalizablePyObjectDerived#__del_derived__()} * first and - if existent - {@link #__del_builtin__()} after that. A plain * {@link FinalizablePyObject#__del__()} - * would behave as overwritten by + * would behave as overridden by * {@link FinalizablePyObjectDerived#__del_derived__()}, i.e. won't be called * if the type implements {@link FinalizablePyObjectDerived}, while * {@link #__del_builtin__()} is called in any case. diff --git a/src/org/python/core/finalization/FinalizablePyObject.java b/src/org/python/core/finalization/FinalizablePyObject.java index 6605633c8..6d5ccd760 100644 --- a/src/org/python/core/finalization/FinalizablePyObject.java +++ b/src/org/python/core/finalization/FinalizablePyObject.java @@ -1,97 +1,69 @@ package org.python.core.finalization; /** - *

    - * This interface allows {@code PyObject}s to have finalizers. - * Alternatively one can use + * This interface allows {@code PyObject}s to have finalizers. Alternatively one can use * {@link org.python.core.finalization.FinalizableBuiltin}. - *

    *

    - * The difference is that {@link #__del__()} can be overwritten by a - * new-style subclass's {@code __del__}-method on Python-side, while - * {@link FinalizableBuiltin#__del_builtin__()} is always called. - * If a Python-side finalizer exists, - * {@link FinalizableBuiltin#__del_builtin__()} will be called after the - * Python-side finalizer has been processed. - *

    + * The difference is that {@link #__del__()} can be overridden by a new-style subclass's + * {@code __del__}-method on Python-side, while {@link FinalizableBuiltin#__del_builtin__()} is + * always called. If a Python-side finalizer exists, {@link FinalizableBuiltin#__del_builtin__()} + * will be called after the Python-side finalizer has been processed. *

    - * One can even implement both interfaces. - * If both interfaces are implemented, the {@link FinalizeTrigger} will - * call {@link #__del__()} first and then - * {@link FinalizableBuiltin#__del_builtin__()}. If a - * new-style subclass has an own, Python-side {@code __del__}-method, this - * overwrites the Java-implemented {@link #__del__()}, but not - * {@link FinalizableBuiltin#__del_builtin__()}, which will be called after - * the Python-side finalizer. - *

    + * One can even implement both interfaces. If both interfaces are implemented, the + * {@link FinalizeTrigger} will call {@link #__del__()} first and then + * {@link FinalizableBuiltin#__del_builtin__()}. If a new-style subclass has an own, Python-side + * {@code __del__}-method, this overrides the Java-implemented {@link #__del__()}, but not + * {@link FinalizableBuiltin#__del_builtin__()}, which will be called after the Python-side + * finalizer. *

    - * If you are writing a custom built-in that shall directly - * extend {@link org.python.core.PyObject} or some other not-yet-finalizable - * builtin and have a finalizer, follow the instructions below. - *

    + * If you are writing a custom built-in that shall directly extend {@link org.python.core.PyObject} + * or some other not-yet-finalizable builtin and have a finalizer, follow the instructions below. *

    *

      - *
    1. - * Let your subclass implement {@link FinalizablePyObject} - * (or {@link FinalizableBuiltin}). - *
    2. - *
    3. - * In every constructor call
      - * {@code FinalizeTrigger.ensureFinalizer(this);}
      - *
    4. - *
    5. - * Write your {@link #__del__()}-method however you intend it. - * (or {@link FinalizableBuiltin#__del_builtin__()} if - * {@link FinalizableBuiltin} was used) - *
    6. - *
    7. - * (optional)
      - * If your finalizer resurrects the object (Python allows this) and you wish the - * finalizer to run again on next collection of the object:
      - * In the block where the resurrection occurs, let your {@link #__del__()}- or - * {@link FinalizableBuiltin#__del_builtin__()}-method call
      - * {@code FinalizeTrigger.ensureFinalizer(this);}. - * If you implement {@code __del__} in Python and need this functionality, you can - * simply call {@code someObject.__ensure_finalizer__()}
      - * Note that this is Jython-specific and should be surrounded by a - * {@code try/except}-block to ensure compatibility with other Python implementations. + *
    8. Let your subclass implement {@link FinalizablePyObject} (or {@link FinalizableBuiltin}).
    9. + *
    10. In every constructor call
      + * {@code FinalizeTrigger.ensureFinalizer(this);}
      *
    11. + *
    12. Write your {@link #__del__()}-method however you intend it. (or + * {@link FinalizableBuiltin#__del_builtin__()} if {@link FinalizableBuiltin} was used)
    13. + *
    14. (optional)
      + * If your finalizer resurrects the object (Python allows this) and you wish the finalizer to run + * again on next collection of the object:
      + * In the block where the resurrection occurs, let your {@link #__del__()}- or + * {@link FinalizableBuiltin#__del_builtin__()}-method call
      + * {@code FinalizeTrigger.ensureFinalizer(this);}. If you implement {@code __del__} in Python and + * need this functionality, you can simply call {@code someObject.__ensure_finalizer__()}
      + * Note that this is Jython-specific and should be surrounded by a {@code try/except}-block to + * ensure compatibility with other Python implementations.
    15. *
    - *

    *

    - * Note: Regarding to object resurrection, Jython currently behaves like CPython >= 3.4. - * That means the finalizer {@link #__del__()} or {@link FinalizableBuiltin#__del_builtin__()} - * is called only the first time an object gets gc'ed. If pre-3.4.-behavior is required for - * some reason (i.e. have the finalizer called repeatedly on every collection after a - * resurrection), one can achieve this manually via step 5). - *

    + * Note: Regarding to object resurrection, Jython currently behaves like CPython ≥ 3.4. That means + * the finalizer {@link #__del__()} or {@link FinalizableBuiltin#__del_builtin__()} is called only + * the first time an object gets gc'ed. If pre-3.4.-behavior is required for some reason (i.e. have + * the finalizer called repeatedly on every collection after a resurrection), one can achieve this + * manually via step 5). *

    - * The built-in function {@code __ensure_finalizer__} is also useful if a class acquires a - * finalizer after instances have already been created. Usually only those instances that were - * created after their class acquired the finalizer will actually be finalized (in contrast to - * CPython). - * However, one can manually tell earlier created instances to become finalizable by - * calling {@code __ensure_finalizer__()} on them. As mentioned above, it is recommended to - * surround this with a {@code try/except}-block to ensure compatibility with other Python - * implementations. - *

    + * The built-in function {@code __ensure_finalizer__} is also useful if a class acquires a finalizer + * after instances have already been created. Usually only those instances that were created after + * their class acquired the finalizer will actually be finalized (in contrast to CPython). However, + * one can manually tell earlier created instances to become finalizable by calling + * {@code __ensure_finalizer__()} on them. As mentioned above, it is recommended to surround this + * with a {@code try/except}-block to ensure compatibility with other Python implementations. *

    - * Note that it is not possible to overwrite {@code __ensure_finalizer__} on Python side. - * If one overwrites {@code __ensure_finalizer__} on Python side, Jython will ignore the - * overwrite-implementation and still call the original one. - *

    + * Note that it is not possible to override {@code __ensure_finalizer__} on Python side. If one + * overrides {@code __ensure_finalizer__} on Python side, Jython will ignore the + * override-implementation and still call the original one. *

    - * It is possible to switch finalization on and off at any desired time for a certain object. - * This can be helpful if it is only necessary to have {@link #__del__()} or + * It is possible to switch finalization on and off at any desired time for a certain object. This + * can be helpful if it is only necessary to have {@link #__del__()} or * {@link FinalizableBuiltin#__del_builtin__()} called for certain configurations of an object. - *

    *

    - * To turn off the finalizer, call
    - * {@code ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).clear();}
    - * To turn it on again, call
    - * {@code ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).trigger(this);} - *

    - * + * To turn off the finalizer, call:
    {@literal
    + * ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).clear();
    + * }
    To turn it on again, call
    {@literal
    + * ((FinalizeTrigger) JyAttribute.getAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)).trigger(this);
    + * }
    + * * @see org.python.core.JyAttribute#FINALIZE_TRIGGER_ATTR * @see FinalizableBuiltin#__del_builtin__() */ diff --git a/src/org/python/core/finalization/FinalizablePyObjectDerived.java b/src/org/python/core/finalization/FinalizablePyObjectDerived.java index 4efcd0d43..049b09d58 100644 --- a/src/org/python/core/finalization/FinalizablePyObjectDerived.java +++ b/src/org/python/core/finalization/FinalizablePyObjectDerived.java @@ -16,7 +16,7 @@ public interface FinalizablePyObjectDerived { * {@code __del_derived__} refers to an instance's in-dict {@code __del__}. * A FinalizeTrigger calls {@code __del_derived__} first and * - if existent - {@code __del_builtin__} after that. A plain {@code __del__} - * would behave as overwritten by {@code __del_derived__}, i.e. won't be called + * would behave as overridden by {@code __del_derived__}, i.e. won't be called * if the type implements {@code FinalizablePyObjectDerived} while * {@code __del_builtin__} is called in any case. */ diff --git a/src/org/python/core/imp.java b/src/org/python/core/imp.java index 96c84cb08..29439b199 100644 --- a/src/org/python/core/imp.java +++ b/src/org/python/core/imp.java @@ -7,8 +7,11 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Date; import java.util.Map; import java.util.concurrent.locks.ReentrantLock; +import java.util.logging.Level; +import java.util.logging.Logger; import org.python.compiler.Module; import org.python.core.util.FileUtil; @@ -24,11 +27,11 @@ */ public class imp { - private static final String IMPORT_LOG = "import"; + private static Logger logger = Logger.getLogger("org.python.import"); private static final String UNKNOWN_SOURCEFILE = ""; - private static final int APIVersion = 37; + private static final int APIVersion = 38; public static final int NO_MTIME = -1; @@ -36,6 +39,14 @@ public class imp { // imports unless `from __future__ import absolute_import` public static final int DEFAULT_LEVEL = -1; + private static final boolean IS_OSX = PySystemState.getNativePlatform().equals("darwin"); + + /** + * A bundle of a file name, the file's content and a last modified time, with no behaviour. As + * used here, the file is a class file and the last modified time is that of the matching + * source, while the filename is taken from the annotation in the class file. See + * {@link imp#readCodeData(String, InputStream, boolean, long)}. + */ public static class CodeData { private final byte[] bytes; @@ -61,8 +72,18 @@ public String getFilename() { } } - public static enum CodeImport { - source, compiled_only; + /** + * A two-way selector given to + * {@link imp#createFromPyClass(String, InputStream, boolean, String, String, long, CodeImport)} + * that tells it whether the source file name to give the module-class constructor, and which + * ends up in {@code co_filename} attribute of the module's {@code PyCode}, should be from the + * caller or the compiled file. + */ + static enum CodeImport { + /** Take the filename from the {@code sourceName} argument */ + source, + /** Take filename from the compiler annotation */ + compiled_only; } /** A non-empty fromlist for __import__'ing sub-modules. */ @@ -74,11 +95,11 @@ public static ClassLoader getSyspathJavaLoader() { /** * Selects the parent class loader for Jython, to be used for dynamically loaded classes and - * resources. Chooses between the current and context classloader based on the following + * resources. Chooses between the current and context class loader based on the following * criteria: * *
      - *
    • If both are the same classloader, return that classloader. + *
    • If both are the same class loader, return that class loader. *
    • If either is null, then the non-null one is selected. *
    • If both are not null, and a parent/child relationship can be determined, then the child * is selected. @@ -87,62 +108,61 @@ public static ClassLoader getSyspathJavaLoader() { * Jython classes) *
    * - * @return the parent class loader for Jython or null if both the current and context - * classloaders are null. + * @return the parent class loader for Jython or null if both the current and context class + * loaders are null. */ public static ClassLoader getParentClassLoader() { ClassLoader current = imp.class.getClassLoader(); ClassLoader context = Thread.currentThread().getContextClassLoader(); - if (context == current) { - return current; - } - if (context == null) { + if (context == current || context == null) { return current; - } - if (current == null) { + } else if (current == null) { return context; - } - if (isParentClassLoader(context, current)) { + } else if (isAncestor(context, current)) { return current; - } - if (isParentClassLoader(current, context)) { + } else if (isAncestor(current, context)) { return context; + } else { + return current; } - return current; } - private static boolean isParentClassLoader(ClassLoader suspectedParent, ClassLoader child) { + /** True iff a {@code possibleAncestor} is the ancestor of the {@code subject}. */ + private static boolean isAncestor(ClassLoader possibleAncestor, ClassLoader subject) { try { - ClassLoader parent = child.getParent(); - if (suspectedParent == parent) { + ClassLoader parent = subject.getParent(); + if (possibleAncestor == parent) { return true; - } - if (parent == null || parent == child) { - // We reached the boot class loader + } else if (parent == null || parent == subject) { + // The subject is the boot class loader return false; + } else { + return isAncestor(possibleAncestor, parent); } - return isParentClassLoader(suspectedParent, parent); - } catch (SecurityException e) { return false; } } - private imp() {} + private imp() {} // Prevent instantiation. /** * If the given name is found in sys.modules, the entry from there is returned. Otherwise a new - * PyModule is created for the name and added to sys.modules + * {@link PyModule} is created for the name and added to {@code sys.modules}. Creating the + * module does not execute the body of the module to initialise its attributes. + * + * @param name fully-qualified name of the module + * @return created {@code PyModule} */ public static PyModule addModule(String name) { name = name.intern(); PyObject modules = Py.getSystemState().modules; - PyModule module = (PyModule)modules.__finditem__(name); + PyModule module = (PyModule) modules.__finditem__(name); if (module != null) { return module; } module = new PyModule(name, null); - PyModule __builtin__ = (PyModule)modules.__finditem__("__builtin__"); + PyModule __builtin__ = (PyModule) modules.__finditem__("__builtin__"); PyObject __dict__ = module.__getattr__("__dict__"); __dict__.__setitem__("__builtins__", __builtin__.__getattr__("__dict__")); __dict__.__setitem__("__package__", Py.None); @@ -151,7 +171,7 @@ public static PyModule addModule(String name) { } /** - * Remove name form sys.modules if it's there. + * Remove name from sys.modules if present. * * @param name the module name */ @@ -170,6 +190,12 @@ private static void removeModule(String name) { } } + /** + * Read a stream as a new byte array and close the stream. + * + * @param fp to read + * @return bytes read + */ private static byte[] readBytes(InputStream fp) { try { return FileUtil.readBytes(fp); @@ -184,6 +210,7 @@ private static byte[] readBytes(InputStream fp) { } } + /** Open a file, raising a {@code PyException} on error. */ private static InputStream makeStream(File file) { try { return new FileInputStream(file); @@ -192,23 +219,69 @@ private static InputStream makeStream(File file) { } } + /** + * As {@link #createFromPyClass(String, InputStream, boolean, String, String, long, CodeImport)} + * but always constructs the named class using {@code sourceName} as argument and makes no check + * on the last-modified time. + * + * @param name module name on which to base the class name as {@code name + "$py"} + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @param sourceName used for identification in messages and the constructor of the named class. + * @param compiledName used for identification in messages and {@code __file__}. + * @return the module or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API mismatch or i/o error. + */ static PyObject createFromPyClass(String name, InputStream fp, boolean testing, String sourceName, String compiledName) { return createFromPyClass(name, fp, testing, sourceName, compiledName, NO_MTIME); - } + /** + * As {@link #createFromPyClass(String, InputStream, boolean, String, String, long, CodeImport)} + * but always constructs the named class using {@code sourceName} as argument. + * + * @param name module name on which to base the class name as {@code name + "$py"} + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @param sourceName used for identification in messages and the constructor of the named class. + * @param compiledName used for identification in messages and {@code __file__}. + * @param sourceLastModified time expected to match {@code MTime} annotation in the class file + * @return the module or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API or last-modified time mismatch or i/o error. + */ static PyObject createFromPyClass(String name, InputStream fp, boolean testing, - String sourceName, String compiledName, long mtime) { - return createFromPyClass(name, fp, testing, sourceName, compiledName, mtime, + String sourceName, String compiledName, long sourceLastModified) { + return createFromPyClass(name, fp, testing, sourceName, compiledName, sourceLastModified, CodeImport.source); } + /** + * Create a Python module from its compiled form, reading the class file from the open input + * stream passed in (which is closed once read). The method may be used in a "testing" mode in + * which the module is imported (if possible), but error conditions return {@code null}, or in a + * non-testing mode where they throw. The caller may choose whether the source file name to give + * the module-class constructor, and which ends up in {@code co_filename} attribute of the + * module's {@code PyCode}, should be {@code sourceName} or the compiled file (See + * {@link CodeImport}.) + * + * @param name module name on which to base the class name as {@code name + "$py"} + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @param sourceName used for identification in messages. + * @param compiledName used for identification in messages and {@code __file__}. + * @param sourceLastModified time expected to match {@code MTime} annotation in the class file + * @param source choose what to use as the file name when initialising the class + * @return the module or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API or last-modified time mismatch or i/o error. + */ static PyObject createFromPyClass(String name, InputStream fp, boolean testing, - String sourceName, String compiledName, long mtime, CodeImport source) { + String sourceName, String compiledName, long sourceLastModified, CodeImport source) { + + // Get the contents of a compiled ($py.class) file and some meta-data CodeData data = null; try { - data = readCodeData(compiledName, fp, testing, mtime); + data = readCodeData(compiledName, fp, testing, sourceLastModified); } catch (IOException ioe) { if (!testing) { throw Py.ImportError(ioe.getMessage() + "[name=" + name + ", source=" + sourceName @@ -218,10 +291,13 @@ static PyObject createFromPyClass(String name, InputStream fp, boolean testing, if (testing && data == null) { return null; } + + // Instantiate the class and have it produce its PyCode object. PyCode code; try { - code = BytecodeLoader.makeCode(name + "$py", data.getBytes(), // - source == CodeImport.compiled_only ? data.getFilename() : sourceName); + // Choose which file name to provide to the module-class constructor + String display = source == CodeImport.compiled_only ? data.getFilename() : sourceName; + code = BytecodeLoader.makeCode(name + "$py", data.getBytes(), display); } catch (Throwable t) { if (testing) { return null; @@ -230,18 +306,42 @@ static PyObject createFromPyClass(String name, InputStream fp, boolean testing, } } - Py.writeComment(IMPORT_LOG, - String.format("import %s # precompiled from %s", name, compiledName)); + // Execute the PyCode object (run the module body) to populate the module __dict__ + logger.log(Level.CONFIG, "import {0} # precompiled from {1}", + new Object[] {name, compiledName}); return createFromCode(name, code, compiledName); } + /** + * As {@link #readCodeData(String, InputStream, boolean, long)} but do not check last-modified + * time and return only the class file bytes as an array. + * + * @param name of source file (used for identification in error/log messages) + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @return the class file bytes as an array or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API or last-modified time mismatch + * @throws IOException from read failures + */ public static byte[] readCode(String name, InputStream fp, boolean testing) throws IOException { return readCode(name, fp, testing, NO_MTIME); } - public static byte[] readCode(String name, InputStream fp, boolean testing, long mtime) - throws IOException { - CodeData data = readCodeData(name, fp, testing, mtime); + /** + * As {@link #readCodeData(String, InputStream, boolean, long)} but return only the class file + * bytes as an array. + * + * @param name of source file (used for identification in error/log messages) + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @param sourceLastModified time expected to match {@code MTime} annotation in the class file + * @return the class file bytes as an array or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API or last-modified time mismatch + * @throws IOException from read failures + */ + public static byte[] readCode(String name, InputStream fp, boolean testing, + long sourceLastModified) throws IOException { + CodeData data = readCodeData(name, fp, testing, sourceLastModified); if (data == null) { return null; } else { @@ -249,17 +349,45 @@ public static byte[] readCode(String name, InputStream fp, boolean testing, long } } + /** + * As {@link #readCodeData(String, InputStream, boolean, long)} but do not check last-modified + * time. + * + * @param name of source file (used for identification in error/log messages) + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @return the {@code CodeData} bundle or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API mismatch + * @throws IOException from read failures + */ public static CodeData readCodeData(String name, InputStream fp, boolean testing) throws IOException { return readCodeData(name, fp, testing, NO_MTIME); } - public static CodeData readCodeData(String name, InputStream fp, boolean testing, long mtime) - throws IOException { - byte[] data = readBytes(fp); - int api; - AnnotationReader ar = new AnnotationReader(data); - api = ar.getVersion(); + /** + * Create a {@link CodeData} object bundling the contents of a class file (given as a stream), + * source-last-modified time supplied, and the name of the file taken from annotations on the + * class. On the way, the method checks the API version annotation matches the current process, + * and that the {@code org.python.compiler.MTime} annotation matches the source-last-modified + * time passed in. + * + * @param name of source file (used for identification in error/log messages) + * @param fp stream from which to read class file (closed when read) + * @param testing if {@code true}, failures are signalled by a {@code null} not an exception + * @param sourceLastModified time expected to match {@code MTime} annotation in the class file + * @return the {@code CodeData} bundle or {@code null} on failure (if {@code testing}). + * @throws PyException {@code ImportError} on API or last-modified time mismatch + * @throws IOException from read failures + */ + public static CodeData readCodeData(String name, InputStream fp, boolean testing, + long sourceLastModified) throws IOException, PyException { + + byte[] classFileData = readBytes(fp); + AnnotationReader ar = new AnnotationReader(classFileData); + + // Check API version fossilised in the class file against that expected + int api = ar.getVersion(); if (api != APIVersion) { if (testing) { return null; @@ -268,32 +396,69 @@ public static CodeData readCodeData(String name, InputStream fp, boolean testing throw Py.ImportError(String.format(fmt, api, APIVersion, name)); } } - if (testing && mtime != NO_MTIME) { - long time = ar.getMTime(); - if (mtime != time) { + + /* + * The source-last-modified time is fossilised in the class file. The source may have been + * installed from a JAR, and this will have resulted in rounding of the last-modified time + * down (see build.xml::jar-sources) to the nearest 2 seconds. + */ + if (testing && sourceLastModified != NO_MTIME) { + long diff = ar.getMTime() - sourceLastModified; + if (diff > 2000L) { // = 2000 milliseconds + logger.log(Level.FINE, "# {0} time is {1} ms later than source", + new Object[] {name, diff}); return null; } } - return new CodeData(data, mtime, ar.getFilename()); + + // All well: make the bundle. + return new CodeData(classFileData, sourceLastModified, ar.getFilename()); } - public static byte[] compileSource(String name, File file) { - return compileSource(name, file, null); + /** + * Compile Python source in file to a class file represented by a byte array. + * + * @param name of module (class name will be name$py) + * @param source file containing the source + * @return Java byte code as array + */ + public static byte[] compileSource(String name, File source) { + return compileSource(name, source, null); } - public static byte[] compileSource(String name, File file, String sourceFilename) { - return compileSource(name, file, sourceFilename, null); + /** + * Compile Python source in file to a class file represented by a byte array. + * + * @param name of module (class name will be name$py) + * @param source file containing the source + * @param filename explicit source file name (or {@code null} to use that in source) + * @return Java byte code as array + */ + public static byte[] compileSource(String name, File source, String filename) { + if (filename == null) { + filename = source.toString(); + } + long mtime = source.lastModified(); + return compileSource(name, makeStream(source), filename, mtime); } - public static byte[] compileSource(String name, File file, String sourceFilename, + /** + * Compile Python source in file to a class file represented by a byte array. + * + * @param name of module (class name will be name$py) + * @param source file containing the source + * @param sourceFilename explicit source file name (or {@code null} to use that in source) + * @param compiledFilename ignored (huh?) + * @return Java byte code as array + * @deprecated Use {@link #compileSource(String, File, String)} instead. + */ + @Deprecated + public static byte[] compileSource(String name, File source, String sourceFilename, String compiledFilename) { - if (sourceFilename == null) { - sourceFilename = file.toString(); - } - long mtime = file.lastModified(); - return compileSource(name, makeStream(file), sourceFilename, mtime); + return compileSource(name, source, sourceFilename); } + /** Remove the last three characters of a file name and add the compiled suffix "$py.class". */ public static String makeCompiledFilename(String filename) { return filename.substring(0, filename.length() - 3) + "$py.class"; } @@ -322,37 +487,50 @@ public static String cacheCompiledSource(String sourceFilename, String compiledF if (man != null) { man.checkWrite(compiledFilename); } - fop = new FileOutputStream(compiledFilename); + fop = new FileOutputStream(FileUtil.makePrivateRW(compiledFilename)); fop.write(compiledSource); fop.close(); return compiledFilename; - } catch (IOException exc) { - // If we can't write the cache file, just log and continue - Py.writeDebug(IMPORT_LOG, "Unable to write to source cache file '" + compiledFilename - + "' due to " + exc); - return null; - } catch (SecurityException exc) { + } catch (IOException | SecurityException exc) { // If we can't write the cache file, just log and continue - Py.writeDebug(IMPORT_LOG, "Unable to write to source cache file '" + compiledFilename - + "' due to " + exc); + logger.log(Level.FINE, "Unable to write to source cache file ''{0}'' due to {1}", + new Object[] {compiledFilename, exc}); return null; } finally { if (fop != null) { try { fop.close(); } catch (IOException e) { - Py.writeDebug(IMPORT_LOG, "Unable to close source cache file '" - + compiledFilename + "' due to " + e); + logger.log(Level.FINE, "Unable to close source cache file ''{0}'' due to {1}", + new Object[] {compiledFilename, e}); } } } } - public static byte[] compileSource(String name, InputStream fp, String filename) { - return compileSource(name, fp, filename, NO_MTIME); + /** + * Compile Python source to a class file represented by a byte array. + * + * @param name of module (class name will be name$py) + * @param source open input stream (will be closed) + * @param filename of source (or {@code null} if unknown) + * @return Java byte code as array + */ + public static byte[] compileSource(String name, InputStream source, String filename) { + return compileSource(name, source, filename, NO_MTIME); } - public static byte[] compileSource(String name, InputStream fp, String filename, long mtime) { + /** + * Compile Python source to a class file represented by a byte array. + * + * @param name of module (class name will be name$py) + * @param source open input stream (will be closed) + * @param filename of source (or {@code null} if unknown) + * @param mtime last-modified time of source, to annotate class + * @return Java byte code as array + */ + public static byte[] compileSource(String name, InputStream source, String filename, + long mtime) { ByteArrayOutputStream ofp = new ByteArrayOutputStream(); try { if (filename == null) { @@ -360,10 +538,12 @@ public static byte[] compileSource(String name, InputStream fp, String filename, } org.python.antlr.base.mod node; try { - node = ParserFacade.parse(fp, CompileMode.exec, filename, new CompilerFlags()); + // Compile source to AST + node = ParserFacade.parse(source, CompileMode.exec, filename, new CompilerFlags()); } finally { - fp.close(); + source.close(); } + // Generate code Module.compile(node, ofp, name + "$py", filename, true, false, null, mtime); return ofp.toByteArray(); } catch (Throwable t) { @@ -380,6 +560,16 @@ public static PyObject createFromSource(String name, InputStream fp, String file return createFromSource(name, fp, filename, outFilename, NO_MTIME); } + /** + * Compile Jython source (as an {@code InputStream}) to a module. + * + * @param name of the module to create (class will be name$py) + * @param fp opened on the (Jython) source to compile (will be closed) + * @param filename of the source backing {@code fp} (to embed in class as data) + * @param outFilename in which to write the compiled class + * @param mtime last modified time of the file backing {@code fp} + * @return created module + */ public static PyObject createFromSource(String name, InputStream fp, String filename, String outFilename, long mtime) { byte[] bytes = compileSource(name, fp, filename, mtime); @@ -387,7 +577,7 @@ public static PyObject createFromSource(String name, InputStream fp, String file outFilename = cacheCompiledSource(filename, outFilename, bytes); } - Py.writeComment(IMPORT_LOG, "'" + name + "' as " + filename); + logger.log(Level.CONFIG, "import {0} # from {1}", new Object[]{name, filename}); PyCode code = BytecodeLoader.makeCode(name + "$py", bytes, filename); return createFromCode(name, code, filename); @@ -402,27 +592,35 @@ public static PyObject createFromCode(String name, PyCode c) { } /** - * Returns a module with the given name whose contents are the results of running c. Sets - * __file__ on the module to be moduleLocation unless moduleLocation is null. If c comes from a - * local .py file or compiled $py.class class moduleLocation should be the result of running new - * File(moduleLocation).getAbsolutePath(). If c comes from a remote file or is a jar - * moduleLocation should be the full uri for c. + * Return a Python module with the given {@code name} whose attributes are the result of running + * {@code PyCode c}. If {@code moduleLocation != null} it is used to set {@code __file__ }. + *

    + * In normal circumstances, if {@code c} comes from a local {@code .py} file or compiled + * {@code $py.class} class the caller should should set {@code moduleLocation} to something like + * {@code new File(moduleLocation).getAbsolutePath()}. If {@code c} comes from a remote file or + * is a JAR, {@code moduleLocation} should be the full URI for that source or class. + * + * @param name fully-qualified name of the module + * @param c code supplying the module + * @param moduleLocation to become {@code __file__} if not {@code null} + * @return the module object */ public static PyObject createFromCode(String name, PyCode c, String moduleLocation) { - PyUnicode.checkEncoding(name); + checkName(name); PyModule module = addModule(name); - PyTableCode code = null; - if (c instanceof PyTableCode) { - code = (PyTableCode)c; + PyBaseCode code = null; + if (c instanceof PyBaseCode) { + code = (PyBaseCode) c; } if (moduleLocation != null) { - module.__setattr__("__file__", new PyString(moduleLocation)); + // Standard library expects __file__ to be encoded bytes + module.__setattr__("__file__", Py.fileSystemEncode(moduleLocation)); } else if (module.__findattr__("__file__") == null) { // Should probably never happen (but maybe with an odd custom builtins, or // Java Integration) - Py.writeDebug(IMPORT_LOG, String.format("Warning: %s __file__ is unknown", name)); + logger.log(Level.WARNING, "{0} __file__ is unknown", name); } ReentrantLock importLock = Py.getSystemState().getImportLock(); @@ -439,18 +637,22 @@ public static PyObject createFromCode(String name, PyCode c, String moduleLocati } } + @SuppressWarnings("unchecked") static PyObject createFromClass(String name, Class c) { // Two choices. c implements PyRunnable or c is Java package if (PyRunnable.class.isAssignableFrom(c)) { try { - return createFromCode(name, ((PyRunnable)c.newInstance()).getMain()); - } catch (InstantiationException e) { - throw Py.JavaError(e); - } catch (IllegalAccessException e) { + if (ContainsPyBytecode.class.isAssignableFrom(c)) { + BytecodeLoader.fixPyBytecode((Class) c); + } + return createFromCode(name, + ((PyRunnable) c.getDeclaredConstructor().newInstance()).getMain()); + } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException + | IOException e) { throw Py.JavaError(e); } } - return PyType.fromClass(c, false); // xxx? + return PyType.fromClass(c); } public static PyObject getImporter(PyObject p) { @@ -458,18 +660,30 @@ public static PyObject getImporter(PyObject p) { return getPathImporter(sys.path_importer_cache, sys.path_hooks, p); } + /** + * Return an importer object for an element of {@code sys.path} or of a package's + * {@code __path__}, possibly by fetching it from the {@code cache}. If it wasn’t yet cached, + * traverse {@code hooks} until a hook is found that can handle the path item. Return + * {@link Py#None} if no hook could do so. This tells our caller it should fall back to the + * built-in import mechanism. Cache the result in {@code cache}. Return a new reference to the + * importer object. + *

    + * This is the "path hooks" mechanism first described in PEP 302 + * + * @param cache normally {@code sys.path_importer_cache} + * @param hooks normally (@code sys.path_hooks} + * @param p an element of {@code sys.path} or of a package's {@code __path__} + * @return the importer object for the path element or {@code Py.None} for "fall-back". + */ static PyObject getPathImporter(PyObject cache, PyList hooks, PyObject p) { - // attempt to get an importer for the path - // use null as default value since Py.None is - // a valid value in the cache for the default - // importer + // Is it in the cache? PyObject importer = cache.__finditem__(p); if (importer != null) { return importer; } - // nothing in the cache, so check all hooks + // Nothing in the cache, so check all hooks. PyObject iter = hooks.__iter__(); for (PyObject hook; (hook = iter.__iternext__()) != null;) { try { @@ -483,6 +697,7 @@ static PyObject getPathImporter(PyObject cache, PyList hooks, PyObject p) { } if (importer == null) { + // No hook claims to handle the location p, so add an imp.NullImporter try { importer = new PyNullImporter(p); } catch (PyException e) { @@ -493,19 +708,32 @@ static PyObject getPathImporter(PyObject cache, PyList hooks, PyObject p) { } if (importer != null) { + // We found an importer. Cache it for next time. cache.__setitem__(p, importer); } else { + // Caller will fall-back to built-in mechanisms. importer = Py.None; } return importer; } + /** + * Try to load a Python module from {@code sys.meta_path}, as a built-in module, or from either + * the {@code __path__} of the enclosing package or {@code sys.path} if the module is being + * sought at the top level. + * + * @param name simple name of the module. + * @param moduleName fully-qualified (dotted) name of the module (ending in {@code name}). + * @param path {@code __path__} of the enclosing package (or {@code null} if top level). + * @return the module if we can load it (or {@code null} if we can't). + */ static PyObject find_module(String name, String moduleName, PyList path) { PyObject loader = Py.None; PySystemState sys = Py.getSystemState(); PyObject metaPath = sys.meta_path; + // Check for importers along sys.meta_path for (PyObject importer : metaPath.asIterable()) { PyObject findModule = importer.__getattr__("find_module"); loader = findModule.__call__(new PyObject[] { // @@ -515,55 +743,67 @@ static PyObject find_module(String name, String moduleName, PyList path) { } } + // Attempt to load from (prepared) builtins in sys.builtins. PyObject ret = loadBuiltin(moduleName); if (ret != null) { return ret; } + // Note the path here may be sys.path or the search path of a Python package. path = path == null ? sys.path : path; - for (int i = 0; i < path.__len__(); i++) { + for (int i = 0; ret == null && i < path.__len__(); i++) { PyObject p = path.__getitem__(i); + // Is there a path-specific importer? PyObject importer = getPathImporter(sys.path_importer_cache, sys.path_hooks, p); if (importer != Py.None) { + // A specific importer is defined. Try its finder method. PyObject findModule = importer.__getattr__("find_module"); loader = findModule.__call__(new PyObject[] {new PyString(moduleName)}); if (loader != Py.None) { return loadFromLoader(loader, moduleName); } } - if (!(p instanceof PyUnicode)) { - p = p.__str__(); - } - ret = loadFromSource(sys, name, moduleName, p.toString()); - if (ret != null) { - return ret; + // p could be a unicode or bytes object (in the file system encoding) + String pathElement = fileSystemDecode(p, false); + if (pathElement != null) { + ret = loadFromSource(sys, name, moduleName, pathElement); } } return ret; } + /** + * Load a built-in module by reference to {@link PySystemState#builtins}, which maps Python + * module names to class names. Special treatment is given to the modules {@code sys} and + * {@code __builtin__}. + * + * @param fully-qualified name of module + * @return the module named + */ private static PyObject loadBuiltin(String name) { + final String MSG = "import {0} # builtin"; if (name == "sys") { - Py.writeComment(IMPORT_LOG, "'" + name + "' as sys in builtin modules"); + logger.log(Level.CONFIG, MSG, name); return Py.java2py(Py.getSystemState()); } if (name == "__builtin__") { - Py.writeComment(IMPORT_LOG, "'" + name + "' as __builtin__ in builtin modules"); + logger.log(Level.CONFIG, MSG, new Object[] {name, name}); return new PyModule("__builtin__", Py.getSystemState().builtins); } String mod = PySystemState.getBuiltin(name); if (mod != null) { - Class c = Py.findClassEx(mod, "builtin modules"); + Class c = Py.findClassEx(mod, "builtin module"); if (c != null) { - Py.writeComment(IMPORT_LOG, "'" + name + "' as " + mod + " in builtin modules"); + logger.log(Level.CONFIG, "import {0} # builtin {1}", new Object[] {name, mod}); try { if (PyObject.class.isAssignableFrom(c)) { // xxx ok? return PyType.fromClass(c); } return createFromClass(name, c); } catch (NoClassDefFoundError e) { - throw Py.ImportError("Cannot import " + name + ", missing class " + c.getName()); + throw Py.ImportError( + "Cannot import " + name + ", missing class " + c.getName()); } } } @@ -571,7 +811,7 @@ private static PyObject loadBuiltin(String name) { } static PyObject loadFromLoader(PyObject importer, String name) { - PyUnicode.checkEncoding(name); + checkName(name); PyObject load_module = importer.__getattr__("load_module"); ReentrantLock importLock = Py.getSystemState().getImportLock(); importLock.lock(); @@ -587,85 +827,160 @@ public static PyObject loadFromCompiled(String name, InputStream stream, String return createFromPyClass(name, stream, false, sourceName, compiledName); } - static PyObject loadFromSource(PySystemState sys, String name, String modName, String entry) { - String dirName = sys.getPath(entry); - String sourceName = "__init__.py"; - String compiledName = "__init__$py.class"; - // display names are for identification purposes (e.g. __file__): when entry is - // null it forces java.io.File to be a relative path (e.g. foo/bar.py instead of - // /tmp/foo/bar.py) - String displayDirName = entry.equals("") ? null : entry.toString(); - String displaySourceName = new File(new File(displayDirName, name), sourceName).getPath(); - String displayCompiledName = - new File(new File(displayDirName, name), compiledName).getPath(); - - // First check for packages - File dir = new File(dirName, name); - File sourceFile = new File(dir, sourceName); - File compiledFile = new File(dir, compiledName); - - boolean pkg = false; + /** + * Import a module defined in Python by loading it from source (or a compiled + * {@code name$pyclass}) file in the specified location (often an entry from {@code sys.path}, + * or a sub-directory of it named for the {@code modName}. For example, if {@code name} is + * "pkg1" and the {@code modName} is "pkg.pkg1", {@code location} might be "mylib/pkg". + * + * @param sys the sys module of the interpreter importing the module. + * @param name by which to look for files or a directory representing the module. + * @param modName name by which to enter the module in {@code sys.modules}. + * @param location where to look for the {@code name}. + * @return the module if we can load it (or {@code null} if we can't). + */ + static PyObject loadFromSource(PySystemState sys, String name, String modName, + String location) { + File sourceFile; // location/name/__init__.py or location/name.py + File compiledFile; // location/name/__init__$py.class or location/name$py.class + boolean haveSource = false, haveCompiled = false; + + // display* names are for mainly identification purposes (e.g. __file__) + String displayLocation = (location.equals("") || location.equals(",")) ? null : location; + String displaySourceName, displayCompiledName; + try { + /* + * Distinguish package and module cases by choosing File objects sourceFile and + * compiledFile based on name/__init__ or name. haveSource and haveCompiled are set true + * if the corresponding source or compiled files exist, and this is what steers the + * loading in the second part of the process. + */ + String dirName = sys.getPath(location); + File dir = new File(dirName, name); + if (dir.isDirectory()) { - if (caseok(dir, name) && (sourceFile.isFile() || compiledFile.isFile())) { - pkg = true; + // This should be a package: location/name + File displayDir = new File(displayLocation, name); + + // Source is location/name/__init__.py + String sourceName = "__init__.py"; + sourceFile = new File(dir, sourceName); + displaySourceName = new File(displayDir, sourceName).getPath(); + + // Compiled is location/name/__init__$py.class + String compiledName = makeCompiledFilename(sourceName); + compiledFile = new File(dir, compiledName); + displayCompiledName = new File(displayDir, compiledName).getPath(); + + // Check the directory name is ok according to case-matching option and platform. + if (caseok(dir, name)) { + haveSource = sourceFile.isFile(); + haveCompiled = compiledFile.isFile(); + } + + if (haveSource || haveCompiled) { + // Create a PyModule (uninitialised) for name, called modName in sys.modules + PyModule m = addModule(modName); + PyString filename = Py.fileSystemEncode(displayDir.getPath()); + m.__dict__.__setitem__("__path__", new PyList(new PyObject[] {filename})); } else { + /* + * There is neither source nor compiled code for __init__.py. In Jython, this + * message warning is premature, as there may be a Java package by this name. + */ + String printDirName = PyString.encode_UnicodeEscape(dir.getPath(), '\''); Py.warning(Py.ImportWarning, String.format( - "Not importing directory '%s': missing __init__.py", dirName)); + "Not importing directory %s: missing __init__.py", printDirName)); } - } - } catch (SecurityException e) { - // ok - } - if (!pkg) { - Py.writeDebug(IMPORT_LOG, "trying source " + dir.getPath()); - sourceName = name + ".py"; - compiledName = name + "$py.class"; - displaySourceName = new File(displayDirName, sourceName).getPath(); - displayCompiledName = new File(displayDirName, compiledName).getPath(); - sourceFile = new File(dirName, sourceName); - compiledFile = new File(dirName, compiledName); - } else { - PyModule m = addModule(modName); - PyObject filename = new PyString(new File(displayDirName, name).getPath()); - m.__dict__.__setitem__("__path__", new PyList(new PyObject[] {filename})); - } + } else { + // This is a (non-package) module: location/name - try { - if (sourceFile.isFile() && caseok(sourceFile, sourceName)) { + // Source is location/name.py + String sourceName = name + ".py"; + sourceFile = new File(dirName, sourceName); // location/name.py + displaySourceName = new File(displayLocation, sourceName).getPath(); + + // Compiled is location/name$py.class + String compiledName = makeCompiledFilename(sourceName); + compiledFile = new File(dirName, compiledName); // location/name$py.class + displayCompiledName = new File(displayLocation, compiledName).getPath(); + + // Check file names exist and ok according to case-matching option and platform. + haveSource = sourceFile.isFile() && caseok(sourceFile, sourceName); + haveCompiled = compiledFile.isFile() && caseok(compiledFile, compiledName); + } + + /* + * Now we are ready to load and execute the module in sourceFile or compiledFile, from + * its compiled or source form, as directed by haveSource and haveCompiled. + */ + if (haveSource) { + // Try to create the module from source or an existing compiled class. long pyTime = sourceFile.lastModified(); - if (compiledFile.isFile() && caseok(compiledFile, compiledName)) { - Py.writeDebug(IMPORT_LOG, "trying precompiled " + compiledFile.getPath()); + + if (haveCompiled) { + // We have the compiled file and will use that if it is not out of date + logger.log(Level.FINE, "# trying precompiled {0}", compiledFile.getPath()); long classTime = compiledFile.lastModified(); if (classTime >= pyTime) { + // The compiled file does not appear out of date relative to the source. PyObject ret = createFromPyClass(modName, makeStream(compiledFile), // true, // OK to fail here as we have the source displaySourceName, displayCompiledName, pyTime); if (ret != null) { return ret; } + } else { + logger.log(Level.FINE, + "# {0} dated ({1,date} {1,time,long}) < ({2,date} {2,time,long})", + new Object[] {name, new Date(classTime), new Date(pyTime)}); } - return createFromSource(modName, makeStream(sourceFile), displaySourceName, - compiledFile.getPath(), pyTime); } + + // The compiled class is not present, is out of date, or using it failed somehow. + logger.log(Level.FINE, "# trying source {0}", sourceFile.getPath()); return createFromSource(modName, makeStream(sourceFile), displaySourceName, compiledFile.getPath(), pyTime); - } - // If no source, try loading precompiled - Py.writeDebug(IMPORT_LOG, "trying precompiled with no source " + compiledFile.getPath()); - if (compiledFile.isFile() && caseok(compiledFile, compiledName)) { + } else if (haveCompiled) { + // There is no source, try loading compiled + logger.log(Level.FINE, "# trying precompiled with no source {0}", + compiledFile.getPath()); return createFromPyClass(modName, makeStream(compiledFile), // false, // throw ImportError here if this fails displaySourceName, displayCompiledName, NO_MTIME, CodeImport.compiled_only); } + } catch (SecurityException e) { - // ok + // We were prevented from reading some essential file, so pretend we didn't find it. } return null; } + /** + * Check that the canonical name of {@code file} matches {@code filename}, case-sensitively, + * even when the OS platform is case-insensitive. This is used to obtain as a check during + * import on platforms (Windows) that may be case-insensitive regarding file open. It is assumed + * that {@code file} was derived from attempting to find {@code filename}, so it returns + * {@code true} on a case-sensitive platform. + *

    + * Algorithmically, we return {@code true} if any of the following is true: + *

      + *
    • {@link Options#caseok} is {@code true} (default is {@code false}).
    • + *
    • The platform is case sensitive (according to + * {@link PlatformUtil#isCaseInsensitive()})
    • + *
    • The name part of the canonical path of {@code file} starts with {@code filename}
    • + *
    • The name of any sibling (in the same directory as) {@code file} equals + * {@code filename}
    • + *
    + * and false otherwise. + * + * @param file to be tested + * @param filename to be matched + * @return {@code file} matches {@code filename} + */ public static boolean caseok(File file, String filename) { if (Options.caseok || !PlatformUtil.isCaseInsensitive()) { return true; @@ -674,13 +989,8 @@ public static boolean caseok(File file, String filename) { File canFile = new File(file.getCanonicalPath()); boolean match = filename.regionMatches(0, canFile.getName(), 0, filename.length()); if (!match) { - // possibly a symlink. Get parent and look for exact match in listdir() - // This is what CPython does in the case of Mac OS X and Cygwin. - // XXX: This will be a performance hit, maybe jdk7 nio2 can give us a better - // method? - File parent = file.getParentFile(); - String[] children = parent.list(); - for (String c : children) { + // Get parent and look for exact match in listdir(). This is horrible, but rare. + for (String c : file.getParentFile().list()) { if (c.equals(filename)) { return true; } @@ -699,7 +1009,7 @@ public static boolean caseok(File file, String filename) { * @return the loaded module */ public static PyObject load(String name) { - PyUnicode.checkEncoding(name); + checkName(name); ReentrantLock importLock = Py.getSystemState().getImportLock(); importLock.lock(); try { @@ -711,17 +1021,17 @@ public static PyObject load(String name) { /** * Find the parent package name for a module. - * + *

    * If __name__ does not exist in the module or if level is 0, then the parent is * null. If __name__ does exist and is not a package name, the containing package * is located. If no such package exists and level is -1, the parent is * null. If level is -1, the parent is the current name. Otherwise, - * level-1 doted parts are stripped from the current name. For example, the + * level-1 dotted parts are stripped from the current name. For example, the * __name__ "a.b.c" and level 2 would return "a.b", if * c is a package and would return "a", if c is not a * package. * - * @param dict the __dict__ of a loaded module + * @param dict the __dict__ of a loaded module that is the context of the import statement * @param level used for relative and absolute imports. -1 means try both, 0 means absolute * only, positive ints represent the level to look upward for a relative path (1 * means current package, 2 means one level up). See PEP 328 at @@ -743,7 +1053,7 @@ private static String get_parent(PyObject dict, int level) { if (!Py.isInstance(tmp, PyString.TYPE)) { throw Py.ValueError("__package__ set to non-string"); } - modname = ((PyString)tmp).getString(); + modname = ((PyString) tmp).getString(); } else { // __package__ not set, so figure it out and set it. @@ -787,138 +1097,234 @@ private static String get_parent(PyObject dict, int level) { if (Py.getSystemState().modules.__finditem__(modname) == null) { if (orig_level < 1) { if (modname.length() > 0) { - Py.warning(Py.RuntimeWarning, String.format("Parent module '%.200s' not found " - + "while handling absolute import", modname)); + Py.warning(Py.RuntimeWarning, String.format( + "Parent module '%.200s' not found " + "while handling absolute import", + modname)); } } else { - throw Py.SystemError(String.format("Parent module '%.200s' not loaded, " - + "cannot perform relative import", modname)); + throw Py.SystemError(String.format( + "Parent module '%.200s' not loaded, " + "cannot perform relative import", + modname)); } } return modname.intern(); } /** + * Try to import the module named by parentName.name. The method tries 3 ways, accepting + * the first that * succeeds: + *

      + *
    1. Check for the module (by its fully-qualified name) in {@code sys.modules}.
    2. + *
    3. If {@code mod==null}, try to load the module via + * {@link #find_module(String, String, PyList)}. If {@code mod!=null}, find it as an attribute + * of {@code mod} via its {@link PyObject#impAttr(String)} method (which then falls back to + * {@code find_module} if {@code mod} has a {@code __path__}). Either way, add the loaded module + * to {@code sys.modules}.
    4. + *
    5. Try to load the module as a Java package by the name {@code outerFullName} + * {@link JavaImportHelper#tryAddPackage(String, PyObject)}.
    6. + *
    + * Finally, if one is found, If a module by the given name already exists in {@code sys.modules} + * it will be returned from there directly. Otherwise, in {@code mod==null} (frequent case) it + * will be looked for via {@link #find_module(String, String, PyList)}. + *

    + * The case {@code mod!=null} supports circumstances in which the module sought may be found as + * an attribute of a parent module. * - * @param mod a previously loaded module - * @param parentNameBuffer - * @param name the name of the module to load - * @return null or None + * @param mod if not {@code null}, a package where the module may be an attribute. + * @param parentName parent name of the module. (Buffer is appended with "." and {@code name}. + * @param name the (simple) name of the module to load + * @param outerFullName name to use with the {@code JavaImportHelper}. + * @param fromlist if not {@code null} the import is {@code from import } + * @return the imported module (or {@code null} or {@link Py#None} on failure). */ - private static PyObject import_next(PyObject mod, StringBuilder parentNameBuffer, String name, + private static PyObject import_next(PyObject mod, StringBuilder parentName, String name, String outerFullName, PyObject fromlist) { - if (parentNameBuffer.length() > 0 && name != null && name.length() > 0) { - parentNameBuffer.append('.'); - } - parentNameBuffer.append(name); - String fullName = parentNameBuffer.toString().intern(); + // Concatenate the parent name and module name *modifying the parent name buffer* + if (parentName.length() > 0 && name != null && name.length() > 0) { + parentName.append('.'); + } + String fullName = parentName.append(name).toString().intern(); + // Check if already in sys.modules (possibly Py.None). PyObject modules = Py.getSystemState().modules; PyObject ret = modules.__finditem__(fullName); if (ret != null) { return ret; } + if (mod == null) { + // We are looking for a top-level module ret = find_module(fullName, name, null); } else { + // Look within mod as enclosing package ret = mod.impAttr(name.intern()); } + if (ret == null || ret == Py.None) { + // Maybe this is a Java package: full name from the import and maybe classes to import if (JavaImportHelper.tryAddPackage(outerFullName, fromlist)) { + // The action has already added it to sys.modules ret = modules.__finditem__(fullName); } return ret; } + + // The find operation may have added to sys.modules the module object we seek. if (modules.__finditem__(fullName) == null) { - modules.__setitem__(fullName, ret); + modules.__setitem__(fullName, ret); // Nope, add it } else { - ret = modules.__finditem__(fullName); + ret = modules.__finditem__(fullName); // Yep, return that instead + } + + // On OSX we currently have to monkeypatch setuptools.command.easy_install. + if (IS_OSX && fullName.equals("setuptools.command")) { + // See http://bugs.jython.org/issue2570 + load("_fix_jython_setuptools_osx"); } + return ret; } - // never returns null or None - private static PyObject import_first(String name, StringBuilder parentNameBuffer) { - PyObject ret = import_next(null, parentNameBuffer, name, null, null); + /** + * Top of the import logic in the case of a simple {@code import a.b.c.m}. + * + * @param name fully-qualified name of module to import {@code import a.b.c.m} + * @param parentName used as a workspace as the search descends the package hierarchy + * @return the named module (never {@code null} or {@code None}) + * @throws PyException {@code ImportError} if not found + */ + private static PyObject import_first(String name, StringBuilder parentName) throws PyException { + PyObject ret = import_next(null, parentName, name, null, null); if (ret == null || ret == Py.None) { throw Py.ImportError("No module named " + name); } return ret; } - private static PyObject import_first(String name, StringBuilder parentNameBuffer, - String fullName, PyObject fromlist) { - PyObject ret = import_next(null, parentNameBuffer, name, fullName, fromlist); + /** + * Top of the import logic in the case of a complex {@code from a.b.c.m import n1, n2, n3}. + * + * @param name fully-qualified name of module to import {@code a.b.c.m}. + * @param parentName used as a workspace as the search descends the package hierarchy + * @param fullName the "outer" name by which the module is known {@code a.b.c.m}. + * @param fromlist names to import from the module {@code n1, n2, n3}. + * @return the named module (never returns {@code null} or {@code None}) + * @throws PyException {@code ImportError} if not found + */ + private static PyObject import_first(String name, StringBuilder parentName, + String fullName, PyObject fromlist) throws PyException { + + // Try the "normal" Python import process + PyObject ret = import_next(null, parentName, name, fullName, fromlist); + + // If unsuccessful try importing as a Java package if (ret == null || ret == Py.None) { if (JavaImportHelper.tryAddPackage(fullName, fromlist)) { - ret = import_next(null, parentNameBuffer, name, fullName, fromlist); + ret = import_next(null, parentName, name, fullName, fromlist); } } + + // If still unsuccessful, it's an error if (ret == null || ret == Py.None) { throw Py.ImportError("No module named " + name); } return ret; } - // Hierarchy-recursively search for dotted name in mod; - // never returns null or None + /** + * Iterate through the components (after the first) of a fully-qualified module name + * {@code a.b.c.m} finding the corresponding modules {@code a.b}, {@code a.b.c}, and + * {@code a.b.c.m}, importing them if necessary. This is a helper to + * {@link #import_module_level(String, boolean, PyObject, PyObject, int)}, used when the module + * name involves more than one level. + *

    + * This method may be called in support of (effectively) of a simple import statement like + * {@code import a.b.c.m} or a complex statement {@code from a.b.c.m import n1, n2, n3}. This + * method always returns the "deepest" name, in the example, the module {@code m} whose full + * name is {@code a.b.c.m}. + * + * @param mod top module of the import + * @param parentName used as a workspace as the search descends the package hierarchy + * @param restOfName {@code b.c.m} + * @param fullName {@code a.b.c.m} + * @param fromlist names to import from the module {@code n1, n2, n3}. + * @return the last named module (never {@code null} or {@code None}) + * @throws PyException {@code ImportError} if not found + */ // ??pending: check if result is really a module/jpkg/jclass? - private static PyObject import_logic(PyObject mod, StringBuilder parentNameBuffer, - String dottedName, String fullName, PyObject fromlist) { + private static PyObject import_logic(PyObject mod, StringBuilder parentName, String restOfName, + String fullName, PyObject fromlist) throws PyException { + int dot = 0; - int last_dot = 0; + int start = 0; do { + // Extract the name that starts at restOfName[start:] up to next dot. String name; - dot = dottedName.indexOf('.', last_dot); + dot = restOfName.indexOf('.', start); if (dot == -1) { - name = dottedName.substring(last_dot); + name = restOfName.substring(start); } else { - name = dottedName.substring(last_dot, dot); + name = restOfName.substring(start, dot); } + PyJavaPackage jpkg = null; if (mod instanceof PyJavaPackage) { - jpkg = (PyJavaPackage)mod; + jpkg = (PyJavaPackage) mod; } - mod = import_next(mod, parentNameBuffer, name, fullName, fromlist); + // Find (and maybe import) the package/module corresponding to this new segment. + mod = import_next(mod, parentName, name, fullName, fromlist); + + // Try harder when importing as a Java package :/ if (jpkg != null && (mod == null || mod == Py.None)) { // try again -- under certain circumstances a PyJavaPackage may // have been added as a side effect of the last import_next // attempt. see Lib/test_classpathimport.py#test_bug1126 - mod = import_next(jpkg, parentNameBuffer, name, fullName, fromlist); + mod = import_next(jpkg, parentName, name, fullName, fromlist); } + + // If still unsuccessful, it's an error if (mod == null || mod == Py.None) { throw Py.ImportError("No module named " + name); } - last_dot = dot + 1; + + // Next module/package simple-name starts just after the last dot we found + start = dot + 1; } while (dot != -1); return mod; } /** - * @param name - * @param top - * @param modDict - * @return a module + * Import a module by name. This supports the default {@code __import__()} function + * {@code __builtin__.__import__}. (Called with the import system locked.) + * + * @param name qualified name of the package/module to import (may be relative) + * @param top if true, return the top module in the name, otherwise the last + * @param modDict the __dict__ of the importing module (used to navigate a relative import) + * @param fromlist list of names being imported + * @param level 0=absolute, n>0=relative levels to go up - 1, -1=try relative then absolute. + * @return an imported module (Java or Python) */ private static PyObject import_module_level(String name, boolean top, PyObject modDict, PyObject fromlist, int level) { + + // Check for basic invalid call if (name.length() == 0) { if (level == 0 || modDict == null) { throw Py.ValueError("Empty module name"); } else { PyObject moduleName = modDict.__findattr__("__name__"); + // XXX: should this test be for "__main__"? if (moduleName != null && moduleName.toString().equals("__name__")) { throw Py.ValueError("Attempted relative import in non-package"); } } } - if (name.indexOf(File.separatorChar) != -1) { - throw Py.ImportError("Import by filename is not supported."); - } + + // Seek the module (in sys.modules) that the import is relative to. PyObject modules = Py.getSystemState().modules; PyObject pkgMod = null; String pkgName = null; @@ -929,6 +1335,8 @@ private static PyObject import_module_level(String name, boolean top, PyObject m pkgMod = null; } } + + // Extract the first element of the (fully qualified) name. int dot = name.indexOf('.'); String firstName; if (dot == -1) { @@ -936,22 +1344,31 @@ private static PyObject import_module_level(String name, boolean top, PyObject m } else { firstName = name.substring(0, dot); } - StringBuilder parentNameBuffer = new StringBuilder(pkgMod != null ? pkgName : ""); - PyObject topMod = import_next(pkgMod, parentNameBuffer, firstName, name, fromlist); + + // Import the first-named module, relative to pkgMod (which may be null) + StringBuilder parentName = new StringBuilder(pkgMod != null ? pkgName : ""); + PyObject topMod = import_next(pkgMod, parentName, firstName, name, fromlist); + if (topMod == Py.None || topMod == null) { - parentNameBuffer = new StringBuilder(""); + // The first attempt failed. + parentName = new StringBuilder(""); // could throw ImportError if (level > 0) { - topMod = import_first(pkgName + "." + firstName, parentNameBuffer, name, fromlist); + // Import relative to context. pkgName was already computed from level. + topMod = import_first(pkgName + "." + firstName, parentName, name, fromlist); } else { - topMod = import_first(firstName, parentNameBuffer, name, fromlist); + // Absolute import + topMod = import_first(firstName, parentName, name, fromlist); } } + PyObject mod = topMod; + if (dot != -1) { - // could throw ImportError - mod = import_logic(topMod, parentNameBuffer, name.substring(dot + 1), name, fromlist); + // This is a dotted name: work through the remaining name elements. + mod = import_logic(topMod, parentName, name.substring(dot + 1), name, fromlist); } + if (top) { return topMod; } @@ -962,10 +1379,85 @@ private static PyObject import_module_level(String name, boolean top, PyObject m return mod; } + /** Defend against attempt to import by filename (withdrawn feature). */ + private static void checkNotFile(String name){ + if (name.indexOf(File.separatorChar) != -1) { + throw Py.ImportError("Import by filename is not supported."); + } + } + + /** + * Enforce ASCII module name, as a guard on module names supplied as an argument. The parser + * guarantees the name from an actual import statement is a valid identifier. + */ + private static void checkName(String name) { + for (int i = name.length(); i > 0;) { + if (name.charAt(--i) > 255) { + throw Py.ImportError("No module named " + name); + } + } + } + + /** + * A wrapper for {@link Py#fileSystemDecode(PyObject)} for project internal use within + * the import mechanism to convert decoding errors that occur during import to either + * {@code null} or {@link Py#ImportError(String)} calls (and a log message), which usually + * results in quiet failure. + * + * @param p assumed to be a (partial) file path + * @param raiseImportError if true and {@code p} cannot be decoded raise {@code ImportError}. + * @return String form of the object {@code p} (or {@code null}). + */ + public static String fileSystemDecode(PyObject p, boolean raiseImportError) { + try { + return Py.fileSystemDecode(p); + } catch (PyException e) { + if (e.match(Py.UnicodeDecodeError)) { + // p is bytes we cannot convert to a String using the FS encoding + if (raiseImportError) { + logger.log(Level.CONFIG, "Cannot decode path entry {0}", p.__repr__()); + throw Py.ImportError("cannot decode"); + } + return null; + } else { + // Any other kind of exception continues as itself + throw e; + } + } + } + + /** + * For project internal use, equivalent to {@code fileSystemDecode(p, true)} (see + * {@link #fileSystemDecode(PyObject, boolean)}). + * + * @param p assumed to be a (partial) file path + * @return String form of the object {@code p}. + */ + public static String fileSystemDecode(PyObject p) { + return fileSystemDecode(p, true); + } + + /** + * Ensure that the items mentioned in the from-list of an import are actually present, even if + * they are modules we have not imported yet. + * + * @param mod module we are importing from + * @param fromlist tuple of names to import + * @param name of module we are importing from (as given, may be relative) + */ private static void ensureFromList(PyObject mod, PyObject fromlist, String name) { ensureFromList(mod, fromlist, name, false); } + /** + * Ensure that the items mentioned in the from-list of an import are actually present, even if + * they are modules we have not imported yet. + * + * @param mod module we are importing from + * @param fromlist tuple of names to import + * @param name of module we are importing from (as given, may be relative) + * @param recursive true, when this method calls itself + */ private static void ensureFromList(PyObject mod, PyObject fromlist, String name, boolean recursive) { // This can happen with imports like "from . import foo" @@ -1004,7 +1496,8 @@ private static void ensureFromList(PyObject mod, PyObject fromlist, String name, * @return an imported module (Java or Python) */ public static PyObject importName(String name, boolean top) { - PyUnicode.checkEncoding(name); + checkNotFile(name); + checkName(name); ReentrantLock importLock = Py.getSystemState().getImportLock(); importLock.lock(); try { @@ -1015,16 +1508,20 @@ public static PyObject importName(String name, boolean top) { } /** - * Import a module by name. This is the default call for __builtin__.__import__. + * Import a module by name. This supports the default {@code __import__()} function + * {@code __builtin__.__import__}. Locks the import system while it operates. * - * @param name the name of the package to import + * @param name the fully-qualified name of the package/module to import * @param top if true, return the top module in the name, otherwise the last - * @param modDict the __dict__ of an already imported module + * @param modDict the __dict__ of the importing module (used for name in relative import) + * @param fromlist list of names being imported + * @param level 0=absolute, n>0=relative levels to go up, -1=try relative then absolute. * @return an imported module (Java or Python) */ public static PyObject importName(String name, boolean top, PyObject modDict, PyObject fromlist, int level) { - PyUnicode.checkEncoding(name); + checkNotFile(name); + checkName(name); ReentrantLock importLock = Py.getSystemState().getImportLock(); importLock.lock(); try { diff --git a/src/org/python/core/io/FileIO.java b/src/org/python/core/io/FileIO.java index ec550ef86..97ab0bd6b 100644 --- a/src/org/python/core/io/FileIO.java +++ b/src/org/python/core/io/FileIO.java @@ -67,22 +67,23 @@ private static class os { * @see #FileIO(PyString name, String mode) */ public FileIO(String name, String mode) { - this(Py.newString(name), mode); + this(Py.newUnicode(name), mode); } /** - * Construct a FileIO instance for the specified file name. + * Construct a FileIO instance for the specified file name, which will be decoded using the + * nominal Jython file system encoding if it is a str/bytes rather than a + * unicode. * - * The mode can be 'r', 'w' or 'a' for reading (default), writing - * or appending. Add a '+' to the mode to allow simultaneous - * reading and writing. + * The mode can be 'r', 'w' or 'a' for reading (default), writing or appending. Add a '+' to the + * mode to allow simultaneous reading and writing. * * @param name the name of the file * @param mode a raw io file mode String */ public FileIO(PyString name, String mode) { parseMode(mode); - File absPath = new RelativeFile(name.toString()); + File absPath = new RelativeFile(Py.fileSystemDecode(name)); try { if ((appending && !(reading || plus)) || (writing && !reading && !plus)) { diff --git a/src/org/python/core/io/IOBase.java b/src/org/python/core/io/IOBase.java index 111c507ef..98a8ea5b1 100644 --- a/src/org/python/core/io/IOBase.java +++ b/src/org/python/core/io/IOBase.java @@ -44,16 +44,31 @@ public long seek(long pos) { } /** - * Seek to byte offset pos relative to position indicated by whence: 0 Start of stream (the - * default). pos should be >= 0; 1 Current position - whence may be negative; 2 End of stream - - * whence usually negative. - * + * Seek to byte offset {@code pos} relative to position indicated by {@code whence}. + *

    Values returned
    NONENo error
    + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Semantics
    {@code whence}Seek to{@code pos}
    0Start of stream (the default).Should be ≥0.
    1Current position + {@code pos} Either sign.
    2End of stream + {@code pos} Usually ≤0.
    * Returns the new absolute position. * - * @param pos - * a long position value - * @param whence - * an int whence value + * @param pos a long position value + * @param whence an int whence value * @return a long position value seeked to */ public long seek(long pos, int whence) { diff --git a/src/org/python/core/packagecache/CachedJarsPackageManager.java b/src/org/python/core/packagecache/CachedJarsPackageManager.java index bb6eed211..43a01bfed 100644 --- a/src/org/python/core/packagecache/CachedJarsPackageManager.java +++ b/src/org/python/core/packagecache/CachedJarsPackageManager.java @@ -4,6 +4,8 @@ package org.python.core.packagecache; import org.python.core.Options; +import org.python.core.PyJavaPackage; +import org.python.core.util.FileUtil; import org.python.util.Generic; import java.io.BufferedInputStream; @@ -19,238 +21,308 @@ import java.lang.reflect.Modifier; import java.net.URL; import java.net.URLConnection; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.BasicFileAttributes; import java.security.AccessControlException; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; /** - * Abstract package manager that gathers info about statically known classes - * from a set of jars. This info can be eventually cached. Off-the-shelf this - * class offers a local file-system based cache impl. + * Abstract package manager that gathers info about statically known classes from a set of jars and + * the Java runtime. This info can be cached, eventually. Off-the-shelf this class offers a local + * file-system based cache implementation. */ public abstract class CachedJarsPackageManager extends PackageManager { + protected static Logger logger = Logger.getLogger("org.python.import"); + /** - * Message log method - hook. This default impl does nothing. + * Message log method - hook. This default implementation does nothing. * - * @param msg message text + * @param msg message template (see java.text.MessageFormat) + * @param params parameters to insert */ - protected void message(String msg) { - } + protected void message(String msg, Object... params) {} /** - * Warning log method - hook. This default impl does nothing. + * Warning log method - hook. This default implementation does nothing. * - * @param warn warning text + * @param msg message template (see java.text.MessageFormat) + * @param params parameters to insert */ - protected void warning(String warn) { - } + protected void warning(String msg, Object... params) {} /** - * Comment log method - hook. This default impl does nothing. + * Comment log method - hook. This default implementation does nothing. * - * @param msg message text + * @param msg message template (see java.text.MessageFormat) + * @param params parameters to insert */ - protected void comment(String msg) { - } + protected void comment(String msg, Object... params) {} /** - * Debug log method - hook. This default impl does nothing. + * Debug log method - hook. This default implementation does nothing. * - * @param msg message text + * @param msg message template (see java.text.MessageFormat) + * @param params parameters to insert */ - protected void debug(String msg) { - } + protected void debug(String msg, Object... params) {} /** - * Filter class/pkg by name helper method - hook. The default impl. is used - * by {@link #addJarToPackages} in order to filter out classes whose name - * contains '$' (e.g. inner classes,...). Should be used or overriden by - * derived classes too. Also to be used in {@link #doDir}. + * Filter class/pkg by name helper method - hook. The default implementation is used by + * {@link #addJarToPackages} in order to filter out classes whose name contains '$' (e.g. inner + * classes). Should be used or overridden by derived classes too. Also to be used in + * {@link #doDir}. * * @param name class/pkg name * @param pkg if true, name refers to a pkg - * @return true if name must be filtered out + * @return {@code true} if name should be filtered out */ protected boolean filterByName(String name, boolean pkg) { return name.indexOf('$') != -1; } /** - * Filter class by access perms helper method - hook. The default impl. is - * used by {@link #addJarToPackages} in order to filter out non-public - * classes. Should be used or overriden by derived classes too. Also to be - * used in {@link #doDir}. Access perms can be read with - * {@link #checkAccess}. + * Filter class by access perms helper method - hook. The default implementation is used by + * {@link #addJarToPackages} in order to filter out non-public classes. Should be used or + * overridden by derived classes too. Also to be used in {@link #doDir}. Access permissions can + * be read with {@link #checkAccess}. * * @param name class name * @param acc class access permissions as int - * @return true if name must be filtered out + * @return {@code true} if name should be filtered out */ protected boolean filterByAccess(String name, int acc) { return (acc & Modifier.PUBLIC) != Modifier.PUBLIC; } + /** + * Set {@code true} whenever the cache index is modified (needs ultimately to be re-written). + */ private boolean indexModified; - private Map jarfiles; + /** + * Map from some source of class definitions to the name of a file used to cache lists of + * classes in that source. {@code null} if cache is not operating. (This source must have a time + * last modified so we may check that the cache is valid). + */ + private Map index; - private static String listToString(List list) { - int n = list.size(); - StringBuilder ret = new StringBuilder(); - for (int i = 0; i < n; i++) { - ret.append(list.get(i)); - if (i < n - 1) { - ret.append(","); - } - } - return ret.toString(); - } + /** + * Process one entry from a JAR/ZIP, and if the entry is a (qualifying) Java class, add its name + * to that package's entry in the map passed in. A class is added only if + * {@link #filterByName(String, boolean)} returns {@code true}. We add it to the accessible or + * inaccessible list according to whether {@link #filterByAccess(String, int)} returns + * {@code true} for the name and permissions of that class. + * + * @param zipPackages map (to update) from package name to class names by accessibility + * @param entry possibly representing a class + * @param zip the JAR or ZIP to which the entry belongs + * @throws IOException + */ + private void addZipEntry(Map zipPackages, ZipEntry entry, ZipInputStream zip) + throws IOException { - // Add a single class from zipFile to zipPackages - // Only add valid, public classes - private void addZipEntry(Map[]> zipPackages, ZipEntry entry, - ZipInputStream zip) throws IOException { String name = entry.getName(); // System.err.println("entry: "+name); - if (!name.endsWith(".class")) { - return; - } - - char sep = '/'; - int breakPoint = name.lastIndexOf(sep); - if (breakPoint == -1) { - breakPoint = name.lastIndexOf('\\'); - sep = '\\'; - } + if (name.endsWith(".class")) { + + // Split off the bare class name + char sep = '/'; + int slash = name.lastIndexOf(sep); + if (slash == -1) { + if ((slash = name.lastIndexOf('\\')) >= 0) { + sep = '\\'; // Shouldn't be necessary according to standards, but is. + } + } + String className = name.substring(slash + 1, name.length() - 6); + + // Check acceptable name: in practice, this is used to ignore inner classes. + if (!filterByName(className, false)) { + // File this class by name against the package + String packageName = slash == -1 ? "" : name.substring(0, slash).replace(sep, '.'); + ClassList classes = zipPackages.get(packageName); + + if (classes == null) { + // It wasn't in the map so add it + classes = new ClassList(); + zipPackages.put(packageName, classes); + } - String packageName; - if (breakPoint == -1) { - packageName = ""; - } else { - packageName = name.substring(0, breakPoint).replace(sep, '.'); + // Put the class on the right list + int access = checkAccess(zip); + if ((access != -1) && !filterByAccess(name, access)) { + classes.accessible.add(className); + } else { + classes.inaccessible.add(className); + } + } } + } - String className = name.substring(breakPoint + 1, name.length() - 6); - - if (filterByName(className, false)) { - return; + /** Used when representing the classes in a particular package. */ + private static class ClassList { + + /** Class names of accessible classes */ + List accessible = new ArrayList(); + /** Class names of inaccessible classes */ + List inaccessible = new ArrayList(); + + /** Retrieve the two lists in "cache file" format {@code A,B,C[@D,E]}. */ + @Override + public String toString() { + StringBuilder buf = new StringBuilder(); + appendList(buf, accessible); + if (inaccessible.size() > 0) { + buf.append('@'); + appendList(buf, inaccessible); + } + return buf.toString(); } - List[] vec = zipPackages.get(packageName); - if (vec == null) { - vec = createGenericStringListArray(); - zipPackages.put(packageName, vec); - } - int access = checkAccess(zip); - if ((access != -1) && !filterByAccess(name, access)) { - vec[0].add(className); - } else { - vec[1].add(className); + private static void appendList(StringBuilder buf, List names) { + if (names.size() > 0) { + for (String n : names) { + buf.append(n).append(','); + } + // Deal with surplus comma + buf.deleteCharAt(buf.length() - 1); + } } } - @SuppressWarnings("unchecked") - private List[] createGenericStringListArray(){ - return new List[] { Generic.list(), Generic.list() }; - } - - // Extract all of the packages in a single jarfile + /** + * Detect all of the packages in an open JAR/ZIP file, that contain any classes for which + * {@link #filterByName(String, boolean)} returns {@code true}. For each such package, list the + * (surviving) classes in two lists: accessible and inaccessible, which is judged according to + * {@link #filterByAccess(String, int)}. The returned map is from package to these two lists, + * now comma-separated lists, with an '@' between them. + * + * @param jarin an open JAR/ZIP file + * @return map from package name to comma/@-separated list of class names + * @throws IOException + */ private Map getZipPackages(InputStream jarin) throws IOException { - Map[]> zipPackages = Generic.map(); + Map zipPackages = Generic.map(); ZipInputStream zip = new ZipInputStream(jarin); - ZipEntry entry; + while ((entry = zip.getNextEntry()) != null) { addZipEntry(zipPackages, entry, zip); zip.closeEntry(); } - // Turn each vector into a comma-separated String + // Turn each ClassList into a comma/@-separated String Map transformed = Generic.map(); - for (Entry[]> kv : zipPackages.entrySet()) { - List[] vec = kv.getValue(); - String classes = listToString(vec[0]); - if (vec[1].size() > 0) { - classes += '@' + listToString(vec[1]); - } - transformed.put(kv.getKey(), classes); + for (Entry kv : zipPackages.entrySet()) { + transformed.put(kv.getKey(), kv.getValue().toString()); } return transformed; } /** - * Gathers classes info from jar specified by jarurl URL. Eventually just - * using previously cached info. Eventually updated info is not cached. - * Persistent cache storage access goes through inOpenCacheFile() and - * outCreateCacheFile(). + * Gathers classes info from jar specified by a URL. Eventually just using previously cached + * info. Eventually updated info is not cached. Persistent cache storage access goes through + * inOpenCacheFile() and outCreateCacheFile(). */ public void addJarToPackages(java.net.URL jarurl) { addJarToPackages(jarurl, null, false); } /** - * Gathers classes info from jar specified by jarurl URL. Eventually just - * using previously cached info. Eventually updated info is (re-)cached if - * param cache is true. Persistent cache storage access goes through - * inOpenCacheFile() and outCreateCacheFile(). + * Gathers classes info from jar specified by URL. Eventually just using previously cached info. + * Eventually updated info is (re-)cached if param cache is true. Persistent cache storage + * access goes through inOpenCacheFile() and outCreateCacheFile(). */ public void addJarToPackages(URL jarurl, boolean cache) { addJarToPackages(jarurl, null, cache); } /** - * Gathers classes info from jar specified by File jarfile. Eventually just - * using previously cached info. Eventually updated info is not cached. - * Persistent cache storage access goes through inOpenCacheFile() and - * outCreateCacheFile(). + * Gathers classes info from jar specified by File jarfile. Eventually just using previously + * cached info. Eventually updated info is not cached. Persistent cache storage access goes + * through inOpenCacheFile() and outCreateCacheFile(). */ public void addJarToPackages(File jarfile) { addJarToPackages(null, jarfile, false); } /** - * Gathers classes info from jar specified by File jarfile. Eventually just - * using previously cached info. Eventually updated info is (re-)cached if - * param cache is true. Persistent cache storage access goes through - * inOpenCacheFile() and outCreateCacheFile(). + * Gathers package and class lists from a jar specified by a {@code File}. Eventually just using + * previously cached info. Eventually updated info is (re-)cached if param cache is true. + * Persistent cache storage access goes through inOpenCacheFile() and outCreateCacheFile(). */ public void addJarToPackages(File jarfile, boolean cache) { addJarToPackages(null, jarfile, cache); } - private void addJarToPackages(URL jarurl, File jarfile, boolean cache) { + /** + * Create (or ensure we have) a {@link PyJavaPackage}, descending from + * {@link PackageManager#topLevelPackage} in this {@link PackageManager} instance, for each + * package in a jar specified by a file or URL. Ensure that the class list in each package is + * updated with the classes this JAR supplies to it. + * + * The information concerning packages in the JAR and the classes they contain, may be read from + * from a previously cached account of the JAR, if the last-modified time of the JAR matches a + * cached value. If it is not read from a cache, it will be obtained by inspecting the JAR, and + * a new cache will be written (if requested). + * + * Access to persistent cache storage goes through {@link #inOpenCacheFile(String)} and + * {@link #outCreateCacheFile(JarXEntry, boolean)}. + * + * @param jarurl identifying the JAR if {@code jarfile} is {@code null} + * @param jarfile identifying the JAR + * @param writeCache re-write the cache if it was out of date (and caching is active). + */ + private void addJarToPackages(URL jarurl, File jarfile, boolean writeCache) { try { - boolean caching = this.jarfiles != null; + // We try to read the cache (for this jar) if caching is in operation. + boolean readCache = this.index != null; + // We write a cache if caching is in operation AND writing has been requested. + writeCache &= readCache; URLConnection jarconn = null; boolean localfile = true; + // If a local JAR file was not given directly in jarfile, try to find one from the URL. if (jarfile == null) { + // We were not given a File, so the URL must be reliable (but may not be a file) jarconn = jarurl.openConnection(); - // This is necessary because 'file:' url-connections - // return always 0 through getLastModified (bug?). - // And in order to handle localfiles (from urls too) - // uniformly. + // The following comment may be out of date. Also 2 reasons or just the bug? + /* + * This is necessary because 'file:' url-connections always return 0 through + * getLastModified (bug?). And in order to handle localfiles (from urls too) + * uniformly. + */ if (jarconn.getURL().getProtocol().equals("file")) { - // ??pending: need to use java2 URLDecoder.decode? + // Although given as a URL, this *is* a file. String jarfilename = jarurl.getFile(); jarfilename = jarfilename.replace('/', File.separatorChar); jarfile = new File(jarfilename); } else { + // We can't find a local file localfile = false; } } if (localfile && !jarfile.exists()) { + // Local JAR file claimed or deduced does not exist. Silently ignore. return; } + // The classes to discover are in a local JAR file. They go in this map: Map zipPackages = null; long mtime = 0; @@ -258,8 +330,9 @@ private void addJarToPackages(URL jarurl, File jarfile, boolean cache) { JarXEntry entry = null; boolean brandNew = false; - if (caching) { + if (readCache) { + // Get the name and last modified time of the actual JAR on disk. if (localfile) { mtime = jarfile.lastModified(); jarcanon = jarfile.getCanonicalPath(); @@ -268,12 +341,14 @@ private void addJarToPackages(URL jarurl, File jarfile, boolean cache) { jarcanon = jarurl.toString(); } - entry = this.jarfiles.get(jarcanon); + // The canonical name is our key in the (in memory) index to the cache file. + entry = this.index.get(jarcanon); - if ((entry == null || !(new File(entry.cachefile).exists())) - && cache) { - comment("processing new jar, '" + jarcanon + "'"); + if (writeCache && (entry == null || !(new File(entry.cachefile).exists()))) { + // We intend to use a cache but there is no valid existing file. + comment("processing new jar ''{0}''", jarcanon); + // Create a base-name for the cache file String jarname; if (localfile) { jarname = jarfile.getName(); @@ -286,62 +361,81 @@ private void addJarToPackages(URL jarurl, File jarfile, boolean cache) { } jarname = jarname.substring(0, jarname.length() - 4); + // Create a new (or replacement) index entry. Remember to create the file. entry = new JarXEntry(jarname); - this.jarfiles.put(jarcanon, entry); - + this.index.put(jarcanon, entry); brandNew = true; } - if (mtime != 0 && entry != null && entry.mtime == mtime) { + // If the source has a date and the cache matches, create the map we need from it. + if (entry != null && mtime != 0 && entry.mtime == mtime) { zipPackages = readCacheFile(entry, jarcanon); } - } + /* + * At this point, we will have the package map from the cache if it was valid, and a + * cache is in use generally in this package manager. + */ + if (zipPackages == null) { - caching = caching && cache; + // We'll have to read the actual JAR file - if (caching) { + if (writeCache) { + // Update the index entry for the cache file we shall eventually write. this.indexModified = true; if (entry.mtime != 0) { - comment("processing modified jar, '" + jarcanon + "'"); + comment("processing modified jar ''{0}''", jarcanon); } entry.mtime = mtime; } + // Create the package-to-class mapping from whatever stream. InputStream jarin = null; try { if (jarconn == null) { - jarin = new BufferedInputStream( - new FileInputStream(jarfile)); + jarin = new BufferedInputStream(new FileInputStream(jarfile)); } else { + // We were given a URL originally so use that. jarin = jarconn.getInputStream(); } zipPackages = getZipPackages(jarin); + } finally { if (jarin != null) { jarin.close(); } } - if (caching) { + if (writeCache) { + // Write what we created out to a cache file (new or updated) writeCacheFile(entry, jarcanon, zipPackages, brandNew); } } + /* + * We now have the package map we need (from a cache or by construction). Now create or + * update corresponding package objects with the discovered classes (named, but not as + * PyObjects). + */ addPackages(zipPackages, jarcanon); + } catch (IOException ioe) { - // silently skip any bad directories - warning("skipping bad jar, '" - + (jarfile != null ? jarfile.toString() : jarurl.toString()) - + "'"); + // Skip the bad JAR with a message + warning("skipping bad jar ''{0}''", (jarfile != null ? jarfile : jarurl).toString()); } - } - private void addPackages(Map zipPackages, String jarfile) { - for (Entry entry : zipPackages.entrySet()) { + /** + * From a map of package name to comma/@-separated list of classes therein, relating to a + * particular JAR file, create a {@link PyJavaPackage} for each package. + * + * @param packageToClasses source of mappings + * @param jarfile becomes the __file__ attribute of the {@link PyJavaPackage} + */ + private void addPackages(Map packageToClasses, String jarfile) { + for (Entry entry : packageToClasses.entrySet()) { String pkg = entry.getKey(); String classes = entry.getValue(); @@ -354,14 +448,16 @@ private void addPackages(Map zipPackages, String jarfile) { } } - // Read in cache file storing package info for a single .jar - // Return null and delete this cachefile if it is invalid + /** + * Read in cache file storing package info for a single jar. Return null and delete this cache + * file if it is invalid. + */ @SuppressWarnings("empty-statement") private Map readCacheFile(JarXEntry entry, String jarcanon) { String cachefile = entry.cachefile; long mtime = entry.mtime; - debug("reading cache, '" + jarcanon + "'"); + debug("reading cache of ''{0}''", jarcanon); DataInputStream istream = null; try { @@ -369,8 +465,8 @@ private Map readCacheFile(JarXEntry entry, String jarcanon) { String old_jarcanon = istream.readUTF(); long old_mtime = istream.readLong(); if ((!old_jarcanon.equals(jarcanon)) || (old_mtime != mtime)) { - comment("invalid cache file: " + cachefile + ", " + jarcanon - + ":" + old_jarcanon + ", " + mtime + ":" + old_mtime); + comment("invalid cache file: {0} for new:{1}({3}), old:{2}({4})", cachefile, jarcanon, + old_jarcanon, mtime, old_mtime); deleteCacheFile(cachefile); return null; } @@ -390,7 +486,7 @@ private Map readCacheFile(JarXEntry entry, String jarcanon) { packs.put(packageName, classes); } } catch (EOFException eof) { - //ignore + // ignore } return packs; @@ -402,23 +498,30 @@ private Map readCacheFile(JarXEntry entry, String jarcanon) { try { istream.close(); } catch (IOException ignore) { - //ignore + // ignore } } } } - // Write a cache file storing package info for a single .jar - private void writeCacheFile(JarXEntry entry, String jarcanon, - Map zipPackages, boolean brandNew) { + /** + * Write a cache file storing package info for a single JAR. * + * + * @param entry in {@link #index} corresponding to the JAR + * @param jarcanon canonical name of the JAR (used as key into {@link #index}) + * @param zipPackages a map from package name to class names for that pacjkage in the JAR + * @param brandNew if the cache file must be created (vs. being re-written) + */ + private void writeCacheFile(JarXEntry entry, String jarcanon, Map zipPackages, + boolean brandNew) { DataOutputStream ostream = null; try { ostream = outCreateCacheFile(entry, brandNew); ostream.writeUTF(jarcanon); ostream.writeLong(entry.mtime); - comment("rewriting cachefile for '" + jarcanon + "'"); + comment("rewriting cache for ''{0}''", jarcanon); - for (Entry kv : zipPackages.entrySet()) { + for (Entry kv : zipPackages.entrySet()) { String classes = kv.getValue(); // Make sure each package is not larger than 64k for (String part : splitString(classes, 65535)) { @@ -428,24 +531,103 @@ private void writeCacheFile(JarXEntry entry, String jarcanon, } } } catch (IOException ioe) { - warning("can't write cache file for '" + jarcanon + "'"); + warning("failed to write cache for ''{0}'' ({1})", jarcanon, ioe.getMessage()); } finally { if (ostream != null) { try { ostream.close(); } catch (IOException ignore) { - //ignore + // ignore } } } } + /** Scan a Java module, creating package objects. */ + protected void addModuleToPackages(Path modulePath) { + try { + comment("reading packages from ''{0}''", modulePath); + Map packages = getModularPackages(modulePath); + addPackages(packages, modulePath.toUri().toString()); + } catch (IOException ioe) { + warning("skipping bad module ''{0}'' ({1})", modulePath, ioe.getMessage()); + } + } + + /** + * Detect all of the packages in a single module, that contain any classes for which + * {@link #filterByName(String, boolean)} returns {@code true}. For each such package, list the + * (surviving) classes in two lists: accessible and inaccessible, which is judged according to + * {@link #filterByAccess(String, int)}. The returned map is from package to these two lists, + * now comma-separated lists, with an '@' between them. + * + * @param modulePath up to and including the name of the module + * @return map from packages to classes + * @throws IOException + */ + private Map getModularPackages(Path modulePath) throws IOException { + + final int M = modulePath.getNameCount(); + final Map modPackages = Generic.map(); + + FileVisitor visitor = new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + //System.out.println(" visitFile:" + file); + + // file starts with modulePath, then has package & class: / ... /[name].class + int n = file.getNameCount(); + // Apply name and access tests and conditionally add to modPackages + String fileName = file.getFileName().toString(); + if (fileName.endsWith(".class") && n > M + 1) { + // Split off the bare class name + String className = fileName.substring(0, fileName.length() - 6); + + // Check acceptable name: in practice, this is used to ignore inner classes. + if (!filterByName(className, false)) { + // Parts M to n-1 define the package of this class + String packageName = file.subpath(M, n - 1).toString().replace('/', '.'); + ClassList classes = modPackages.get(packageName); + + if (classes == null) { + // It wasn't in the map so add it + classes = new ClassList(); + modPackages.put(packageName, classes); + } + + // Put the class on the accessible or inaccessible list + try (InputStream c = Files.newInputStream(file, StandardOpenOption.READ)) { + int access = checkAccess(c); + if ((access != -1) && !filterByAccess(fileName, access)) { + classes.accessible.add(className); + } else { + classes.inaccessible.add(className); + } + } + } + } + return FileVisitResult.CONTINUE; + } + }; + + Files.walkFileTree(modulePath, visitor); + + // Turn each ClassList into a comma/@-separated String + Map transformed = Generic.map(); + for (Entry kv : modPackages.entrySet()) { + transformed.put(kv.getKey(), kv.getValue().toString()); + } + + return transformed; + } + /** * Split up a string into several chunks based on a certain size * - * The writeCacheFile method will use the writeUTF method on a - * DataOutputStream which only allows writing 64k chunks, so use - * this utility method to split it up + * The writeCacheFile method will use the writeUTF method on a DataOutputStream which only + * allows writing 64k chunks, so use this utility method to split it up * * @param str - The string to split up into chunks * @param maxLength - The max size a string should be @@ -470,12 +652,12 @@ protected static String[] splitString(String str, int maxLength) { } /** - * Initializes cache. Eventually reads back cache index. Index persistent - * storage is accessed through inOpenIndex(). + * Initialise the cache by reading the index from storage, through {@link #inOpenIndex()}, or by + * creating a new empty one. */ protected void initCache() { this.indexModified = false; - this.jarfiles = Generic.map(); + this.index = Generic.map(); DataInputStream istream = null; try { @@ -489,10 +671,10 @@ protected void initCache() { String jarcanon = istream.readUTF(); String cachefile = istream.readUTF(); long mtime = istream.readLong(); - this.jarfiles.put(jarcanon, new JarXEntry(cachefile, mtime)); + this.index.put(jarcanon, new JarXEntry(cachefile, mtime)); } } catch (EOFException eof) { - //ignore + // ignore } } catch (IOException ioe) { warning("invalid index file"); @@ -501,18 +683,20 @@ protected void initCache() { try { istream.close(); } catch (IOException ignore) { - //ignore + // ignore } } } } /** - * Write back cache index. Index persistent storage is accessed through + * Write back cache index. The index is a mapping from each source of class definitions + * to the file where the cache for that source is held. This list is accessed through * outOpenIndex(). */ public void saveCache() { - if (jarfiles == null || !indexModified) { + + if (index == null || !indexModified) { return; } @@ -523,7 +707,7 @@ public void saveCache() { DataOutputStream ostream = null; try { ostream = outOpenIndex(); - for (Entry entry : jarfiles.entrySet()) { + for (Entry entry : index.entrySet()) { String jarcanon = entry.getKey(); JarXEntry xentry = entry.getValue(); ostream.writeUTF(jarcanon); @@ -531,13 +715,13 @@ public void saveCache() { ostream.writeLong(xentry.mtime); } } catch (IOException ioe) { - warning("can't write index file"); + warning("failed to write index file ({0})", ioe.getMessage()); } finally { if (ostream != null) { try { ostream.close(); } catch (IOException ignore) { - //ignore + // ignore } } } @@ -546,11 +730,14 @@ public void saveCache() { // hooks for changing cache storage /** - * To pass a cachefile id by ref. And for internal use. See - * outCreateCacheFile + * Class of object used to represent a cache file and last modification time, internally and to + * {@link CachedJarsPackageManager#outCreateCacheFile}. When caching, a {@code JarXEntry} is + * created for each JAR processed for classes, and corresponds to a file in the package cache + * directory. The name is based on the name of the JAR. */ public static class JarXEntry extends Object { - /** cachefile id */ + + /** Specifies the actual cache file once that is created or opened. */ public String cachefile; public long mtime; @@ -567,116 +754,107 @@ public JarXEntry(String cachefile, long mtime) { } /** - * Open cache index for reading from persistent storage - hook. Must Return - * null if this is absent. This default impl is part of the off-the-shelf - * local file-system cache impl. Can be overriden. + * Open cache index for reading from persistent storage – hook. Must Return null if this + * is absent. This default implementation is part of the off-the-shelf local file-system cache + * implementation. Can be overridden. */ protected DataInputStream inOpenIndex() throws IOException { File indexFile = new File(this.cachedir, "packages.idx"); - if (!indexFile.exists()) { return null; + } else { + FileInputStream istream = new FileInputStream(indexFile); + return new DataInputStream(new BufferedInputStream(istream)); } - - DataInputStream istream = new DataInputStream(new BufferedInputStream( - new FileInputStream(indexFile))); - - return istream; } /** - * Open cache index for writing back to persistent storage - hook. This - * default impl is part of the off-the-shelf local file-system cache impl. - * Can be overriden. + * Open cache index for writing back to persistent storage – hook. This default + * implementation is part of the off-the-shelf local file-system cache implementation. Can be + * overridden. */ protected DataOutputStream outOpenIndex() throws IOException { - File indexFile = new File(this.cachedir, "packages.idx"); - - return new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(indexFile))); + File indexFile = FileUtil.makePrivateRW(new File(this.cachedir, "packages.idx")); + FileOutputStream ostream = new FileOutputStream(indexFile); + return new DataOutputStream(new BufferedOutputStream(ostream)); } /** - * Open cache file for reading from persistent storage - hook. This default - * impl is part of the off-the-shelf local file-system cache impl. Can be - * overriden. + * Open a particular cache file for reading from persistent storage. This default implementation + * is part of the off-the-shelf local file-system cache implementation. Can be overridden. */ - protected DataInputStream inOpenCacheFile(String cachefile) - throws IOException { - return new DataInputStream(new BufferedInputStream(new FileInputStream( - cachefile))); + protected DataInputStream inOpenCacheFile(String cachefile) throws IOException { + return new DataInputStream(new BufferedInputStream(new FileInputStream(cachefile))); } /** - * Delete (invalidated) cache file from persistent storage - hook. This - * default impl is part of the off-the-shelf local file-system cache impl. - * Can be overriden. + * Delete (invalidated) cache file from persistent storage - hook. This default implementation + * is part of the off-the-shelf local file-system cache implementation. Can be overridden. */ protected void deleteCacheFile(String cachefile) { new File(cachefile).delete(); } /** - * Create/open cache file for rewriting back to persistent storage - hook. - * If create is false, cache file is supposed to exist and must be opened - * for rewriting, entry.cachefile is a valid cachefile id. If create is - * true, cache file must be created. entry.cachefile is a flat jarname to be - * used to produce a valid cachefile id (to be put back in entry.cachefile - * on exit). This default impl is part of the off-the-shelf local - * file-system cache impl. Can be overriden. + * Create/open cache file for rewriting back to persistent storage – hook. If + * {@code create} is {@code false}, the cache file is supposed to exist at + * {@code entry.cachefile} and will be opened for rewriting. If {@code create} is {@code true}, + * {@code entry.cachefile} is the base name (e.g. JAR or module name) for a cache to be created, + * and the full name will be put in {@code entry.cachefile} on exit. This default implementation + * is part of the off-the-shelf local file-system cache implementation. It may be overridden to + * provide a different cache medium and use of {@code entry.cachefile}. + * + * @param entry cache file description + * @param create new or use existing file named in {@code entry.cachefile} + * @return stream on which to represent the package to class-list textually + * @throws IOException */ - protected DataOutputStream outCreateCacheFile(JarXEntry entry, - boolean create) throws IOException { - File cachefile = null; + protected DataOutputStream outCreateCacheFile(JarXEntry entry, boolean create) + throws IOException { + + File file; if (create) { - int index = 1; - String suffix = ""; + // Create a new cache file with a name based on the initial value String jarname = entry.cachefile; - while (true) { - cachefile = new File(this.cachedir, jarname + suffix + ".pkc"); - // System.err.println("try cachefile: "+cachefile); - if (!cachefile.exists()) { - break; - } - suffix = "$" + index; - index += 1; + file = new File(this.cachedir, jarname + ".pkc"); + for (int index = 1; file.exists(); index++) { + // That name is in use: make up another one. + file = new File(this.cachedir, jarname + "$" + index + ".pkc"); } - entry.cachefile = cachefile.getCanonicalPath(); + file = FileUtil.makePrivateRW(file); + entry.cachefile = file.getCanonicalPath(); + } else { - cachefile = new File(entry.cachefile); + // Use an existing cache file named in the entry + file = new File(entry.cachefile); } - return new DataOutputStream(new BufferedOutputStream( - new FileOutputStream(cachefile))); + return new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); } - // for default cache (local fs based) impl - + /** Directory in which cache files are stored. */ private File cachedir; /** - * Initialize off-the-shelf (default) local file-system cache impl. Must be - * called before {@link #initCache}. cachedir is the cache repository - * directory, this is eventually created. Returns true if dir works. + * Initialize off-the-shelf (default) local file-system cache implementation. Must be called + * before {@link #initCache}. cachedir is the cache repository directory, this is eventually + * created. Returns true if dir works. */ - protected boolean useCacheDir(File aCachedir1) { - if (aCachedir1 == null) { - return false; - } + protected boolean useCacheDir(File cachedir) { try { - if(!aCachedir1.isDirectory() && aCachedir1.mkdirs() == false) { - warning("can't create package cache dir, '" + aCachedir1 + "'"); - return false; + if (cachedir != null) { + if (cachedir.isDirectory() || cachedir.mkdirs()) { + this.cachedir = cachedir; + return true; + } else { + warning("failed to create cache dir ''{0}''", cachedir); + } } - } catch(AccessControlException ace) { - warning("The java security manager isn't allowing access to the package cache dir, '" + aCachedir1 + "'"); - return false; + } catch (AccessControlException ace) { + warning("Not permitted to access cache ''{0}'' ({1})", cachedir, ace.getMessage()); } - - this.cachedir = aCachedir1; - - return true; + return false; } } diff --git a/src/org/python/core/packagecache/PackageManager.java b/src/org/python/core/packagecache/PackageManager.java index 757e092e7..60e27ddef 100644 --- a/src/org/python/core/packagecache/PackageManager.java +++ b/src/org/python/core/packagecache/PackageManager.java @@ -11,16 +11,19 @@ import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyStringMap; -import org.python.core.util.FileUtil; import java.io.IOException; import java.io.InputStream; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.StringTokenizer; /** * Abstract package manager. */ public abstract class PackageManager extends Object { + /** Nominal top-level package of all (Java) packages, containing "java", "com", "org", etc.. */ public PyJavaPackage topLevelPackage; public PackageManager() { @@ -33,12 +36,11 @@ public Class findClass(String pkg, String name) { return findClass(pkg, name, "java class"); } - public void notifyPackageImport(String pkg, String name) { - } + public void notifyPackageImport(String pkg, String name) {} /** - * Dynamically check if pkg.name exists as java pkg in the controlled - * hierarchy. Should be overriden. + * Dynamically check if pkg.name exists as java pkg in the controlled hierarchy. Should be + * overridden. * * @param pkg parent pkg name * @param name candidate name @@ -47,7 +49,7 @@ public void notifyPackageImport(String pkg, String name) { public abstract boolean packageExists(String pkg, String name); /** - * Reports the specified package content names. Should be overriden. Used by + * Reports the specified package content names. Should be overridden. Used by * {@link PyJavaPackage#__dir__} and {@link PyJavaPackage#fillDir}. * * @return resulting list of names (PyList of PyString) @@ -55,39 +57,34 @@ public void notifyPackageImport(String pkg, String name) { * @param instantiate if true then instatiate reported names in package dict * @param exclpkgs exclude packages (just when instantiate is false) */ - public abstract PyList doDir(PyJavaPackage jpkg, boolean instantiate, - boolean exclpkgs); + public abstract PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs); /** - * Append a directory to the list of directories searched for java packages - * and java classes. + * Append a directory to the list of directories searched for java packages and java classes. * * @param dir A directory. */ public abstract void addDirectory(java.io.File dir); /** - * Append a directory to the list of directories searched for java packages - * and java classes. + * Append a directory to the list of directories searched for java packages and java classes. * * @param dir A directory name. */ public abstract void addJarDir(String dir, boolean cache); /** - * Append a jar file to the list of locations searched for java packages and - * java classes. + * Append a jar file to the list of locations searched for java packages and java classes. * * @param jarfile A directory name. */ public abstract void addJar(String jarfile, boolean cache); /** - * Basic helper implementation of {@link #doDir}. It merges information - * from jpkg {@link PyJavaPackage#clsSet} and {@link PyJavaPackage#__dict__}. + * Basic helper implementation of {@link #doDir}. It merges information from jpkg + * {@link PyJavaPackage#clsSet} and {@link PyJavaPackage#__dict__}. */ - protected PyList basicDoDir(PyJavaPackage jpkg, boolean instantiate, - boolean exclpkgs) { + protected PyList basicDoDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyStringMap dict = jpkg.__dict__; PyStringMap cls = jpkg.clsSet; @@ -117,17 +114,24 @@ protected PyList basicDoDir(PyJavaPackage jpkg, boolean instantiate, return dict.keys(); } - /** - * Helper merging list2 into list1. Returns list1. - */ + /** Helper merging list2 into list1. Returns list1. */ protected PyList merge(PyList list1, PyList list2) { for (PyObject name : list2.asIterable()) { list1.append(name); } - return list1; } + /** + * Given the (dotted) name of a package, find the {@link PyJavaPackage} corresponding, by + * navigating from the {@link #topLevelPackage}, successively applying + * {@link PyObject#__findattr__(String)}. This in fact drives the creation of + * {@link PyJavaPackage} objects since it indirectly calls + * {@link #packageExists(String, String)}. + * + * @param name (dotted) package name + * @return the package named + */ public PyObject lookupName(String name) { PyObject top = this.topLevelPackage; do { @@ -150,41 +154,38 @@ public PyObject lookupName(String name) { } /** - * Creates package/updates statically known classes info. Uses - * {@link PyJavaPackage#addPackage(java.lang.String, java.lang.String) }, + * Create (or ensure we have) a {@link PyJavaPackage} for the named package and add to it the + * names of classes mentioned here. These classes are added as "place holders" only, so they + * become members of it, without being instantiated. This method relies on + * {@link PyJavaPackage#addPackage(java.lang.String, java.lang.String)} and * {@link PyJavaPackage#addPlaceholders}. * * @param name package name - * @param classes comma-separated string - * @param jarfile involved jarfile; can be null + * @param classes comma or @-sign separated string + * @param jarfile involved; can be null * @return created/updated package */ - public PyJavaPackage makeJavaPackage(String name, String classes, - String jarfile) { + public PyJavaPackage makeJavaPackage(String name, String classes, String jarfile) { PyJavaPackage p = this.topLevelPackage; if (name.length() != 0) { p = p.addPackage(name, jarfile); } - - if (classes != null) { - p.addPlaceholders(classes); - } - + p.addPlaceholders(split(classes, ",@")); return p; } - + /** ASM visitor class supporting {@link #checkAccess(InputStream)}. */ private static class AccessVisitor extends ClassVisitor { private int class_access; public AccessVisitor() throws IOException { - super(Opcodes.ASM5); + super(Opcodes.ASM7); } @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { + public void visit(int version, int access, String name, String signature, String superName, + String[] interfaces) { class_access = access; } @@ -194,11 +195,10 @@ public int getClassAccess() { } /** - * Check that a given stream is a valid Java .class file. And return its - * access permissions as an int. + * Check that a given stream is a valid Java .class file, and return its access permissions as + * an int. */ - static protected int checkAccess(java.io.InputStream cstream) - throws IOException { + static protected int checkAccess(InputStream cstream) throws IOException { try { ClassReader reader = new ClassReader(cstream); AccessVisitor visitor = new AccessVisitor(); @@ -209,4 +209,30 @@ static protected int checkAccess(java.io.InputStream cstream) } } + /** + * Helper to split a textual list into a list. The semantics are basically those of + * {@code StringTokenizer}, followed by {@code String.trim()} and duplicate removal. + * + * @param target compound string to split into tokens ({@code null} treated as "". + * @param sep characters, any of which will be treated as a token separator + * @return set of tokens trimmed of white space + */ + protected static Set split(String target, String sep) { + Set result = new LinkedHashSet<>(); + if (target != null) { + StringTokenizer tok = new StringTokenizer(target, sep); + while (tok.hasMoreTokens()) { + String entry = tok.nextToken().trim(); + if (entry.length() > 0) { + result.add(entry); + } + } + } + return result; + } + + /** Equivalent to {@code split(target, ",")}. See {@link #split(String, String)}. */ + protected static Set split(String target) { + return split(target, ","); + } } diff --git a/src/org/python/core/packagecache/PathPackageManager.java b/src/org/python/core/packagecache/PathPackageManager.java index 659f4dafa..766dfd83d 100644 --- a/src/org/python/core/packagecache/PathPackageManager.java +++ b/src/org/python/core/packagecache/PathPackageManager.java @@ -3,25 +3,25 @@ package org.python.core.packagecache; -import org.python.core.imp; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.logging.Level; + import org.python.core.Py; +import org.python.core.PyException; import org.python.core.PyJavaPackage; import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyUnicode; +import org.python.core.imp; import org.python.core.util.RelativeFile; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FilenameFilter; -import java.io.IOException; - /** - * Path package manager. Gathering classes info dynamically from a set of - * directories in path {@link #searchPath}, and statically from a set of jars, - * like {@link CachedJarsPackageManager}. + * Path package manager. Gathering classes info dynamically from a set of directories in path + * {@link #searchPath}, and statically from a set of jars, like {@link CachedJarsPackageManager}. */ public abstract class PathPackageManager extends CachedJarsPackageManager { @@ -32,101 +32,93 @@ public PathPackageManager() { } /** - * Helper for {@link #packageExists(java.lang.String,java.lang.String)}. - * Scans for package pkg.name the directories in path. + * Helper for {@link #packageExists(String,String)}. Scans the directories in the given path for + * package pkg.name. A directory with a matching name is considered to define a package if it + * contains no Python (source or compiled), or contains a Java .class file (not compiled from + * Python). */ - protected boolean packageExists(PyList path, String pkg, String name) { - String child = pkg.replace('.', File.separatorChar) + File.separator - + name; + protected static boolean packageExists(PyList path, String pkg, String name) { + String child = pkg.replace('.', File.separatorChar) + File.separator + name; for (int i = 0; i < path.__len__(); i++) { + PyObject entry = path.pyget(i); - if (!(entry instanceof PyUnicode)) { - entry = entry.__str__(); - } - String dir = entry.toString(); - - File f = new RelativeFile(dir, child); - try { - if (f.isDirectory() && imp.caseok(f, name)) { - /* - * Figure out if we have a directory a mixture of python and - * java or just an empty directory (which means Java) or a - * directory with only Python source (which means Python). - */ - PackageExistsFileFilter m = new PackageExistsFileFilter(); - f.listFiles(m); - boolean exists = m.packageExists(); - if (exists) { - Py.writeComment("import", "java package as '" - + f.getAbsolutePath() + "'"); + + // Each entry in the path may be byte-encoded or unicode + String dir = imp.fileSystemDecode(entry, false); + if (dir != null) { + File f = new RelativeFile(dir, child); + try { + if (f.isDirectory() && imp.caseok(f, name)) { + /* + * f is a directory matching the package name. This directory is considered + * to define a package if it contains no Python (source or compiled), or + * contains a Java .class file (not compiled from Python). + */ + PackageExistsFileFilter m = new PackageExistsFileFilter(); + f.listFiles(m); + boolean exists = m.packageExists(); + if (exists) { + logger.log(Level.CONFIG, "# trying {0}", f.getAbsolutePath()); + } + return exists; } - return exists; + } catch (SecurityException se) { + return false; } - } catch (SecurityException se) { - return false; } } return false; } private static class PackageExistsFileFilter implements FilenameFilter { - private boolean java; + private boolean java; private boolean python; @Override public boolean accept(File dir, String name) { - if(name.endsWith(".py") || name.endsWith("$py.class") || name.endsWith("$_PyInner.class")) { + if (name.endsWith(".py") || name.endsWith("$py.class") + || name.endsWith("$_PyInner.class")) { python = true; - }else if (name.endsWith(".class")) { + } else if (name.endsWith(".class")) { java = true; } return false; } public boolean packageExists() { - if (this.python && !this.java) { - return false; - } - return true; + return !python || java; } } /** - * Helper for {@link #doDir(PyJavaPackage,boolean,boolean)}. Scans for - * package jpkg content over the directories in path. Add to ret the found - * classes/pkgs. Filter out classes using {@link #filterByName},{@link #filterByAccess}. + * Helper for {@link #doDir(PyJavaPackage,boolean,boolean)}. Scans for package jpkg content over + * the directories in path. Add to ret the found classes/pkgs. Filter out classes using + * {@link #filterByName},{@link #filterByAccess}. */ - protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, - boolean instantiate, boolean exclpkgs) { + protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, boolean instantiate, + boolean exclpkgs) { + String child = jpkg.__name__.replace('.', File.separatorChar); for (int i = 0; i < path.__len__(); i++) { - PyObject entry = path.pyget(i); - if (!(entry instanceof PyUnicode)) { - entry = entry.__str__(); - } - String dir = entry.toString(); - + // Each entry in the path may be byte-encoded or unicode + String dir = Py.fileSystemDecode(path.pyget(i)); if (dir.length() == 0) { dir = null; } File childFile = new File(dir, child); - String[] list = childFile.list(); if (list == null) { continue; } - doList: for (int j = 0; j < list.length; j++) { + doList : for (int j = 0; j < list.length; j++) { String jname = list[j]; - File cand = new File(childFile, jname); - int jlen = jname.length(); - boolean pkgCand = false; if (cand.isDirectory()) { @@ -166,8 +158,7 @@ protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, if (!pkgCand) { try { - int acc = checkAccess(new BufferedInputStream( - new FileInputStream(cand))); + int acc = checkAccess(new BufferedInputStream(new FileInputStream(cand))); if ((acc == -1) || filterByAccess(jname, acc)) { continue; } @@ -185,15 +176,11 @@ protected void doDir(PyList path, PyList ret, PyJavaPackage jpkg, } ret.append(name); - } } - } - /** - * Add directory dir (if exists) to {@link #searchPath}. - */ + /** Add directory dir (if exists) to {@link #searchPath}. */ @Override public void addDirectory(File dir) { try { @@ -203,29 +190,20 @@ public void addDirectory(File dir) { this.searchPath.append(Py.newStringOrUnicode(dir.getCanonicalPath())); } } catch (IOException e) { - warning("skipping bad directory, '" + dir + "'"); + warning("# skipping bad directory {0} ({1})", dir, e.getMessage()); } } - // ??pending: - // Uses simply split and not a StringTokenizer+trim to adhere to - // sun jvm parsing of classpath. - // E.g. "a;" is parsed by sun jvm as a, ""; the latter is interpreted - // as cwd. jview trims and cwd is per default in classpath. - // The logic here should work for both(...). Need to distinguish? - // This code does not avoid duplicates in searchPath. - // Should cause no problem (?). - /** - * Adds "classpath" entry. Calls {@link #addDirectory} if path refers to a - * dir, {@link #addJarToPackages(java.io.File, boolean)} with param cache - * true if path refers to a jar. + * Scan a Java class-path that may be a mixture of directory and JAR specifiers, and within each + * path entry index the packages. Calls {@link #addDirectory} if a path entry refers to a dir, + * {@link #addJarToPackages(java.io.File, boolean)} with param cache true if the path entry + * refers to a jar. */ public void addClassPath(String path) { - PyList paths = new PyString(path).split(java.io.File.pathSeparator); - - for (int i = 0; i < paths.__len__(); i++) { - String entry = paths.pyget(i).toString(); + String[] entries = path.split(java.io.File.pathSeparator); + for (String entry : entries) { + entry = entry.trim(); if (entry.endsWith(".jar") || entry.endsWith(".zip")) { addJarToPackages(new File(entry), true); } else { @@ -238,13 +216,10 @@ public void addClassPath(String path) { } @Override - public PyList doDir(PyJavaPackage jpkg, boolean instantiate, - boolean exclpkgs) { + public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); PyList ret = new PyList(); - doDir(this.searchPath, ret, jpkg, instantiate, exclpkgs); - return merge(basic, ret); } diff --git a/src/org/python/core/packagecache/SysPackageManager.java b/src/org/python/core/packagecache/SysPackageManager.java index 1772cae53..83411240b 100644 --- a/src/org/python/core/packagecache/SysPackageManager.java +++ b/src/org/python/core/packagecache/SysPackageManager.java @@ -7,34 +7,51 @@ import org.python.core.PyJavaPackage; import org.python.core.PyList; import org.python.core.PySystemState; +import org.python.core.RegistryKey; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; import java.util.Properties; +import java.util.Set; import java.util.StringTokenizer; -import java.io.*; +import java.util.logging.Level; +import java.util.logging.Logger; /** * System package manager. Used by org.python.core.PySystemState. */ public class SysPackageManager extends PathPackageManager { + private static Logger pkglog = Logger.getLogger("org.python.package"); + @Override - protected void message(String msg) { - Py.writeMessage("*sys-package-mgr*", msg); + protected void message(String msg, Object... params) { + pkglog.log(Level.INFO, msg, params); } @Override - protected void warning(String warn) { - Py.writeWarning("*sys-package-mgr*", warn); + protected void warning(String msg, Object... params) { + pkglog.log(Level.WARNING, msg, params); } @Override - protected void comment(String msg) { - Py.writeComment("*sys-package-mgr*", msg); + protected void comment(String msg, Object... params) { + pkglog.log(Level.CONFIG, msg, params); } @Override - protected void debug(String msg) { - Py.writeDebug("*sys-package-mgr*", msg); + protected void debug(String msg, Object... params) { + pkglog.log(Level.FINE, msg, params); } public SysPackageManager(File cachedir, Properties registry) { @@ -58,60 +75,133 @@ public void addJarDir(String jdir, boolean cache) { addJarDir(jdir, cache, cache); } + /** + * Index the contents of every JAR or ZIP in a directory. + * + * @param jdir directory containing some JAR or ZIP files + * @param cache + * @param saveCache + */ private void addJarDir(String jdir, boolean cache, boolean saveCache) { + File file = new File(jdir); - if (!file.isDirectory()) { - return; - } String[] files = file.list(); - for (int i = 0; i < files.length; i++) { - String entry = files[i]; - if (entry.endsWith(".jar") || entry.endsWith(".zip")) { - addJarToPackages(new File(jdir, entry), cache); + + if (files != null) { + // jdir is a directory, enumerated in the array files + for (int i = 0; i < files.length; i++) { + String entry = files[i]; + if (entry.endsWith(".jar") || entry.endsWith(".zip")) { + addJarToPackages(new File(jdir, entry), cache); + } + } + + if (saveCache) { + saveCache(); } - } - if (saveCache) { - saveCache(); } } + /** + * Scan a path that contains directory specifiers, and within each directory, find every JAR or + * ZIP archive and add it to the list of archives searched for packages. (This means, index it.) + * Non-directory entries are ignored. + */ private void addJarPath(String path) { - StringTokenizer tok = new StringTokenizer(path, - java.io.File.pathSeparator); + StringTokenizer tok = new StringTokenizer(path, java.io.File.pathSeparator); while (tok.hasMoreTokens()) { // ??pending: do jvms trim? how is interpreted entry=""? String entry = tok.nextToken(); + // Use the extra flag to defer writing out the cache. addJarDir(entry, true, false); } } + /** + * Index the packages in every module in a directory. Entries in the directory that are not modules + * (do not contain a {@code module-info.class}) are ignored. Only modules exploded on the file system of this path are (currently) supported, + * and at the time of writing, we only use this method on the {@code jrt:} file system. + * + * @param moduleDir directory containing some modules + */ + private void addModuleDir(final Path moduleDir) { + try { + // Walk the directory tree with this visitor + FileVisitor visitor = new SimpleFileVisitor() { + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + // System.out.println(dir); + if (dir.equals(moduleDir)) { + // Ignore this, it's just the root) + } else if (Files.exists(dir.resolve("module-info.class"))) { + // dir is a module: scan packages from it. + addModuleToPackages(dir); + return FileVisitResult.SKIP_SUBTREE; + } + return FileVisitResult.CONTINUE; + } + }; + + Files.walkFileTree(moduleDir, visitor); + + } catch (IOException e) { + warning("error enumerating Java modules in {0}: {1}", moduleDir, e.getMessage()); + } + } + + /** + * Walk the packages found in paths specified indirectly through the given {@code Properties} + * object. + * + * @param registry in practice, the Jython registry + */ private void findAllPackages(Properties registry) { - String paths = registry.getProperty("python.packages.paths", - "java.class.path,sun.boot.class.path"); - String directories = registry.getProperty( - "python.packages.directories", "java.ext.dirs"); - String fakepath = registry - .getProperty("python.packages.fakepath", null); - StringTokenizer tok = new StringTokenizer(paths, ","); - while (tok.hasMoreTokens()) { - String entry = tok.nextToken().trim(); - String tmp = registry.getProperty(entry); - if (tmp == null) { - continue; + + /* + * Packages in the Java runtime environment are enumerated in the jrt file system (from Java + * 9 onwards), or in JARs and directories designated by the properties + * sun.boot.class.path and java.ext.dirs (up to Java 8). + */ + String defaultClassPaths, defaultDirectories; + try { + // Support for the modular JVM (particular packages). + FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/")); + addModuleDir(jrtfs.getPath("/modules/")); + defaultClassPaths = "java.class.path"; + defaultDirectories = ""; + } catch (ProviderNotFoundException e) { + // Running on a JVM before Java 9: add boot class path and optional extensions. + defaultClassPaths = "java.class.path,sun.boot.class.path"; + defaultDirectories = "java.ext.dirs"; + } + + Set cps = split(registry.getProperty( + RegistryKey.PYTHON_PACKAGES_PATHS, defaultClassPaths)); + for (String name : cps) { + // Each property is a class-path string containing JARS and directories + String classPath = registry.getProperty(name); + if (classPath != null) { + // Each path may be a mixture of directory and JAR specifiers (source of packages) + addClassPath(classPath); } - addClassPath(tmp); } - tok = new StringTokenizer(directories, ","); - while (tok.hasMoreTokens()) { - String entry = tok.nextToken().trim(); - String tmp = registry.getProperty(entry); - if (tmp == null) { - continue; + Set directories = + split(registry.getProperty( + RegistryKey.PYTHON_PACKAGES_DIRECTORIES, + defaultDirectories)); + for (String name : directories) { + // Each property defines a path string containing directories + String path = registry.getProperty(name); + if (path != null) { + // Add the JAR/ZIP archives in those directories to the search path for packages + addJarPath(path); } - addJarPath(tmp); } + String fakepath = registry.getProperty( + RegistryKey.PYTHON_PACKAGES_FAKEPATH, null); if (fakepath != null) { addClassPath(fakepath); } @@ -120,16 +210,17 @@ private void findAllPackages(Properties registry) { @Override public void notifyPackageImport(String pkg, String name) { if (pkg != null && pkg.length() > 0) { - name = pkg + '.' + name; + comment("import {0} # as java package {1}.{0}", name); + } else { + comment("import {0} # as java package", name); } - Py.writeComment("import", "'" + name + "' as java package"); } @Override public Class findClass(String pkg, String name) { Class c = super.findClass(pkg, name); if (c != null) { - Py.writeComment("import", "'" + name + "' as java class"); + comment("import {0} # as java class", name); } return c; } @@ -143,17 +234,15 @@ public Class findClass(String pkg, String name, String reason) { } @Override - public PyList doDir(PyJavaPackage jpkg, boolean instantiate, - boolean exclpkgs) { + public PyList doDir(PyJavaPackage jpkg, boolean instantiate, boolean exclpkgs) { PyList basic = basicDoDir(jpkg, instantiate, exclpkgs); PyList ret = new PyList(); doDir(this.searchPath, ret, jpkg, instantiate, exclpkgs); - PySystemState system = Py.getSystemState(); - - if (system.getClassLoader() == null) { - doDir(system.path, ret, jpkg, instantiate, exclpkgs); + PySystemState sys = Py.getSystemState(); + if (sys.getClassLoader() == null) { + doDir(sys.path, ret, jpkg, instantiate, exclpkgs); } return merge(basic, ret); @@ -163,16 +252,9 @@ public PyList doDir(PyJavaPackage jpkg, boolean instantiate, public boolean packageExists(String pkg, String name) { if (packageExists(this.searchPath, pkg, name)) { return true; + } else { + PySystemState sys = Py.getSystemState(); + return sys.getClassLoader() == null && packageExists(sys.path, pkg, name); } - - PySystemState system = Py.getSystemState(); - - if (system.getClassLoader() == null - && packageExists(Py.getSystemState().path, pkg, name)) { - return true; - } - - return false; } - } diff --git a/src/org/python/core/stringlib/FloatFormatter.java b/src/org/python/core/stringlib/FloatFormatter.java index 86784831c..621f1b963 100644 --- a/src/org/python/core/stringlib/FloatFormatter.java +++ b/src/org/python/core/stringlib/FloatFormatter.java @@ -30,7 +30,7 @@ public class FloatFormatter extends InternalFormat.Formatter { private int lenMarker; /** The length of the exponent sign and digits or zero if there isn't one. */ private int lenExponent; - /** if >=0, minimum digits to follow decimal point (where consulted) */ + /** if ≥0, minimum digits to follow decimal point (where consulted) */ private int minFracDigits; /** @@ -85,7 +85,7 @@ public static int size(Spec spec) { * formats remove trailing zero digits, trimming to zero or one. Set member * minFracDigits, to modify this behaviour. * - * @param minFracDigits if <0 prevent truncation; if >=0 the minimum number of fractional + * @param minFracDigits if <0 prevent truncation; if ≥0 the minimum number of fractional * digits; when this is zero, and all fractional digits are zero, the decimal point * will also be removed. */ @@ -436,6 +436,7 @@ private void ensurePointAndTrailingZeros(int n) { * these recommended values: * * + * * * * diff --git a/src/org/python/core/stringlib/IntegerFormatter.java b/src/org/python/core/stringlib/IntegerFormatter.java index 92e8c6dda..48958b80a 100644 --- a/src/org/python/core/stringlib/IntegerFormatter.java +++ b/src/org/python/core/stringlib/IntegerFormatter.java @@ -327,7 +327,10 @@ void format_d(int value) { if (value < 0) { // Negative value: deal with sign and base, and convert magnitude. negativeSign(null); - number = Integer.toString(-value); + // Here there is a special case for int min value due to wrapping, to avoid a double + // negative sign being added see http://bugs.jython.org/issue2672 + // The string constant here is -Integer.MIN_VALUE + number = value == Integer.MIN_VALUE ? "2147483648" : Integer.toString(-value); } else { // Positive value: deal with sign, base and magnitude. positiveSign(null); diff --git a/src/org/python/core/stringlib/InternalFormat.java b/src/org/python/core/stringlib/InternalFormat.java index 091b0dc49..4e6111111 100644 --- a/src/org/python/core/stringlib/InternalFormat.java +++ b/src/org/python/core/stringlib/InternalFormat.java @@ -316,6 +316,7 @@ protected void uppercase() { * When the padding method has decided that that it needs to add n padding characters, it * will affect {@link #start} or {@link #lenWhole} as follows. *
    Recommended values for formatting arguments
    typeprecision
    + * * * * @@ -324,28 +325,28 @@ protected void uppercase() { * * * - * + * * * * * * * - * + * * * * * * * - * + * * * * * * * - * + * * * * @@ -428,7 +429,7 @@ protected void pad(int leftIndex, int n) { } /** - * Fix-up the zero-padding of the last formatted number in {@link #result()} in the special + * Fix-up the zero-padding of the last formatted number in {@link #result} in the special * case where a sign-aware padding ({@link #spec}.align='=') was requested, the * fill character is '0', and the digits are to be grouped. In these exact * circumstances, the grouping, which must already have been applied to the (whole part) @@ -655,7 +656,7 @@ public static PyException precisionTooLarge(String type) { * * A typical idiom is: * - *
    +     * 
    {@literal
          *     private static final InternalFormatSpec FLOAT_DEFAULTS = InternalFormatSpec.from(">");
          *     ...
          *         InternalFormat.Spec spec = InternalFormat.fromText(specString);
    @@ -663,17 +664,13 @@ public static PyException precisionTooLarge(String type) {
          *         ... // Validation of spec.type, and other attributes, for this type.
          *         FloatFormatter f = new FloatFormatter(spec);
          *         String result = f.format(value).getResult();
    -     *
    -     * 
    + * }
    */ public static class Spec { /** The fill character specified, or U+FFFF if unspecified. */ public final char fill; - /** - * Alignment indicator is one of {'<', '^', '>', '=', or U+FFFF if - * unspecified. - */ + /** Alignment indicator is one of {'<', '^', '>', '=', or U+FFFF if unspecified. */ public final char align; /** * Sign-handling flag, one of '+', '-', or ' ', or @@ -710,7 +707,7 @@ public static final boolean specified(char c) { * Test to see if an attribute has been specified. * * @param value of attribute - * @return true only if the attribute is >=0 (meaning that it has been specified). + * @return true only if the attribute is ≥0 (meaning that it has been specified). */ public static final boolean specified(int value) { return value >= 0; @@ -724,7 +721,7 @@ public static final boolean specified(int value) { * * * @param fill fill character (or {@link #NONE} - * @param align alignment indicator, one of {'<', '^', '>', '=' + * @param align alignment indicator, one of {'<', '^', '>', '='} * @param sign policy, one of '+', '-', or ' '. * @param alternate true to request alternate formatting mode ('#' flag). * @param width of field after padding or -1 to default @@ -785,8 +782,8 @@ public String toString() { * defaults may also be unspecified.) The use of this method is to allow a Spec * constructed from text to record exactly, and only, what was in the textual specification, * while the __format__ method of a client object supplies its type-specific defaults. Thus - * "20" means "<20s" to a str, ">20.12" to a float and ">20.12g" - * to a complex. + * "20" means "<20s" to a str, ">20.12" to a float and + * ">20.12g" to a complex. * * @param other defaults to merge where this object does not specify the attribute. * @return a new Spec object. @@ -804,15 +801,11 @@ public Spec withDefaults(Spec other) { ); } - /** - * Defaults applicable to most numeric types. Equivalent to " >" - */ + /** Defaults applicable to most numeric types. Equivalent to " >" */ public static final Spec NUMERIC = new Spec(' ', '>', Spec.NONE, false, Spec.UNSPECIFIED, false, Spec.UNSPECIFIED, Spec.NONE); - /** - * Defaults applicable to string types. Equivalent to " <" - */ + /** Defaults applicable to string types. Equivalent to " <" */ public static final Spec STRING = new Spec(' ', '<', Spec.NONE, false, Spec.UNSPECIFIED, false, Spec.UNSPECIFIED, Spec.NONE); diff --git a/src/org/python/core/stringlib/MarkupIterator.java b/src/org/python/core/stringlib/MarkupIterator.java index 2f5104d10..2fb1783df 100644 --- a/src/org/python/core/stringlib/MarkupIterator.java +++ b/src/org/python/core/stringlib/MarkupIterator.java @@ -142,7 +142,7 @@ private PyObject wrap(String value, String defaultValue) { /** * Return the next {@link Chunk} from the iterator, which is a structure containing parsed * elements of the replacement field (if any), and its preceding text. This is the Java - * equivalent of the tuple returned by {@link __iternext__()}. This finds use in the + * equivalent of the tuple returned by {@link #__iternext__()}. This finds use in the * implementation of str.format and unicode.format. * * @return the chunk diff --git a/src/org/python/core/util/ByteSwapper.java b/src/org/python/core/util/ByteSwapper.java index 1fe724bcf..dc1cac300 100644 --- a/src/org/python/core/util/ByteSwapper.java +++ b/src/org/python/core/util/ByteSwapper.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,9 +28,9 @@ *
  • float
  • *
  • double
  • * - *

    + * * Note this functionality is provided in the base types since 1.5. - * + * * @author Andrew Howard */ public class ByteSwapper { @@ -38,7 +38,7 @@ public class ByteSwapper { /** * Reverses the byte order of all elements in the supplied array, converting * between little and big endian byte order. - * + * * @param array the input array for type sensitive byte swapping. */ public static void swap(Object array) { @@ -68,7 +68,7 @@ public static void swap(Object array) { /** * Byte order reverses an Array of doubles - * + * * @param array input array */ private static void swapDoubleArray(Object array) { @@ -99,7 +99,7 @@ private static void swapDoubleArray(Object array) { /** * Byte order reverses an Array of floats - * + * * @param array input array */ private static void swapFloatArray(Object array) { @@ -125,7 +125,7 @@ private static void swapFloatArray(Object array) { /** * Byte order reverses an Array of ints - * + * * @param array input array */ private static void swapIntegerArray(Object array) { @@ -148,7 +148,7 @@ private static void swapIntegerArray(Object array) { /** * Byte order reverses an Array of longs - * + * * @param array input array */ private static void swapLongArray(Object array) { @@ -176,7 +176,7 @@ private static void swapLongArray(Object array) { /** * Byte order reverses an Array of shorts - * + * * @param array input array */ private static void swapShortArray(Object array) { diff --git a/src/org/python/core/util/ExtraMath.java b/src/org/python/core/util/ExtraMath.java index a8de28e80..8a2e11d5f 100644 --- a/src/org/python/core/util/ExtraMath.java +++ b/src/org/python/core/util/ExtraMath.java @@ -43,13 +43,14 @@ public static double closeFloor(double v) { *

    * For sufficiently small x*10n, the rounding is to zero, and the return value * is a signed zero (same sign as x). Suppose x = a*2b, where the significand - * we must have a<2. Sufficiently small means such that n log210 < + * we must have a<2. Sufficiently small means such that n log210 < * -(b+2). *

    * For sufficiently large x*10n, the adjustment of rounding is too small to * affect the least significant bit. That is a*2b represents an amount greater * than one, and rounding no longer affects the value, and the return is x. Since the matissa - * has 52 fractional bits, sufficiently large means such that n log210 > 52-b. + * has 52 fractional bits, sufficiently large means such that n log210 > + * 52-b. * * @param x to round * @param n decimal places diff --git a/src/org/python/core/util/FileUtil.java b/src/org/python/core/util/FileUtil.java index 23879f66e..a8fa07482 100644 --- a/src/org/python/core/util/FileUtil.java +++ b/src/org/python/core/util/FileUtil.java @@ -2,6 +2,7 @@ package org.python.core.util; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -72,7 +73,7 @@ public static PyFile wrap(OutputStream os) { } /** - * Read all bytes from the input stream.

    Note that using this method to + * Read all bytes from the input stream.

    Note that using this method to * read very large streams could cause out-of-memory exceptions and/or block * for large periods of time. */ @@ -90,4 +91,35 @@ public static byte[] readBytes(InputStream in) throws IOException { } return out.toByteArray(); } + + /** + * Create the named file (if necessary) and give just the owner read-write access. + * + * @param filename to create/control + * @return {@code File} object for subsequent open + * @throws IOException + */ + public static File makePrivateRW(String filename) throws IOException { + return makePrivateRW(new File(filename)); + } + + /** + * Create the identified file (if necessary) and give just the owner read-write access. + * + * @param file to create/control + * @return {@code File} object for subsequent open + * @throws IOException + */ + public static File makePrivateRW(File file) throws IOException { + file.createNewFile(); + // Remove permissions for all + file.setReadable(false, false); + file.setWritable(false, false); + file.setExecutable(false, false); + // Add permissions for owner + file.setReadable(true); + file.setWritable(true); + return file; + } + } diff --git a/src/org/python/core/util/StringUtil.java b/src/org/python/core/util/StringUtil.java index 1feaf8d04..3835552f1 100644 --- a/src/org/python/core/util/StringUtil.java +++ b/src/org/python/core/util/StringUtil.java @@ -95,7 +95,8 @@ public static String fromBytes(BaseBytes b) { } /** - * Decapitalize a String if it begins with a capital letter, e.g.: FooBar -> fooBar + * Decapitalize a String if it begins with a capital letter, e.g.: + * {@code decapitalize("FooBar") == "fooBar"} * * @param string a String * @return a decapitalized String diff --git a/src/org/python/core/util/importer.java b/src/org/python/core/util/importer.java index 3e943a11d..25222b8b9 100644 --- a/src/org/python/core/util/importer.java +++ b/src/org/python/core/util/importer.java @@ -4,6 +4,8 @@ import java.io.IOException; import java.io.InputStream; import java.util.EnumSet; +import java.util.logging.Logger; +import java.util.logging.Level; import org.python.core.BytecodeLoader; import org.python.core.Py; @@ -20,6 +22,8 @@ */ public abstract class importer extends PyObject { + protected static Logger logger = Logger.getLogger("org.python.import"); + static enum EntryType { IS_SOURCE, IS_BYTECODE, IS_PACKAGE }; @@ -80,10 +84,11 @@ public importer() { protected abstract Bundle makeBundle(String filenameAndSuffix, T entry); private SearchOrderEntry[] makeSearchOrder(){ + String initName = "__init__.py"; return new SearchOrderEntry[] { - new SearchOrderEntry(getSeparator() + "__init__$py.class", + new SearchOrderEntry(getSeparator() + imp.makeCompiledFilename(initName), EnumSet.of(EntryType.IS_PACKAGE, EntryType.IS_BYTECODE)), - new SearchOrderEntry(getSeparator() + "__init__.py", + new SearchOrderEntry(getSeparator() + initName, EnumSet.of(EntryType.IS_PACKAGE, EntryType.IS_SOURCE)), new SearchOrderEntry("$py.class", EnumSet.of(EntryType.IS_BYTECODE)), new SearchOrderEntry(".py", EnumSet.of(EntryType.IS_SOURCE)),}; @@ -113,7 +118,8 @@ protected final PyObject importer_load_module(String fullname) { mod.__dict__.__setitem__("__path__", pkgpath); } imp.createFromCode(fullname, moduleCodeData.code, moduleCodeData.path); - Py.writeDebug("import", "import " + fullname + " # loaded from " + moduleCodeData.path); + logger.log(Level.FINE, "import {0} # loaded from {1}", + new Object[] {fullname, moduleCodeData.path}); return mod; } @@ -198,7 +204,7 @@ protected final ModuleCodeData getModuleCode(String fullname) { String searchPath = path + suffix; String fullSearchPath = fullPath + suffix; - Py.writeDebug("import", "# trying " + searchPath); + logger.log(Level.FINE, "# trying {0}", searchPath); T tocEntry = makeEntry(searchPath); if (tocEntry == null) { continue; diff --git a/src/org/python/expose/BaseTypeBuilder.java b/src/org/python/expose/BaseTypeBuilder.java index e7ebd6f39..d7d6aac97 100644 --- a/src/org/python/expose/BaseTypeBuilder.java +++ b/src/org/python/expose/BaseTypeBuilder.java @@ -16,7 +16,7 @@ public class BaseTypeBuilder implements TypeBuilder { private PyDataDescr[] descrs; - private Class typeClass; + private Class typeClass; private Class baseClass; @@ -27,7 +27,7 @@ public class BaseTypeBuilder implements TypeBuilder { private String doc; public BaseTypeBuilder(String name, - Class typeClass, + Class typeClass, Class baseClass, boolean isBaseType, String doc, @@ -44,8 +44,9 @@ public BaseTypeBuilder(String name, this.newWrapper = newWrapper; } + @Override public PyObject getDict(PyType type) { - PyObject dict = new PyStringMap(); + PyStringMap dict = new PyStringMap(); for(PyBuiltinMethod func : meths) { PyMethodDescr pmd = func.makeDescriptor(type); dict.__setitem__(pmd.getName(), pmd); @@ -61,22 +62,27 @@ public PyObject getDict(PyType type) { return dict; } + @Override public String getName() { return name; } - public Class getTypeClass() { + @Override + public Class getTypeClass() { return typeClass; } + @Override public Class getBase() { return baseClass; } + @Override public boolean getIsBaseType() { return isBaseType; } + @Override public String getDoc() { return doc; } diff --git a/src/org/python/expose/TypeBuilder.java b/src/org/python/expose/TypeBuilder.java index 67ca1e935..3fef8526b 100644 --- a/src/org/python/expose/TypeBuilder.java +++ b/src/org/python/expose/TypeBuilder.java @@ -12,9 +12,9 @@ public interface TypeBuilder { public PyObject getDict(PyType type); - public Class getTypeClass(); + public Class getTypeClass(); - public Class getBase(); + public Class getBase(); public boolean getIsBaseType(); diff --git a/src/org/python/expose/generate/ExposeTask.java b/src/org/python/expose/generate/ExposeTask.java index 0b5a53109..acd1ba217 100644 --- a/src/org/python/expose/generate/ExposeTask.java +++ b/src/org/python/expose/generate/ExposeTask.java @@ -8,8 +8,6 @@ import org.apache.tools.ant.BuildException; import org.objectweb.asm.ClassWriter; -import org.python.core.Py; -import org.python.core.Options; import org.python.util.GlobMatchingTask; public class ExposeTask extends GlobMatchingTask { @@ -32,14 +30,7 @@ public void process(Set toExpose) throws BuildException { log("Exposing 1 class"); } - // Quiet harmless unbootstrapped warnings during the expose process - int verbose = Options.verbose; - Options.verbose = Py.ERROR; - try { - expose(toExpose); - } finally { - Options.verbose = verbose; - } + expose(toExpose); } private void expose(Set toExpose) { diff --git a/src/org/python/expose/generate/ExposedFieldFinder.java b/src/org/python/expose/generate/ExposedFieldFinder.java index 6cddf7789..1cf2c958a 100644 --- a/src/org/python/expose/generate/ExposedFieldFinder.java +++ b/src/org/python/expose/generate/ExposedFieldFinder.java @@ -14,7 +14,7 @@ public abstract class ExposedFieldFinder extends FieldVisitor implements PyTypes private String doc; public ExposedFieldFinder(String name, FieldVisitor delegate) { - super(Opcodes.ASM5); + super(Opcodes.ASM7); fieldName = name; this.delegate = delegate; } diff --git a/src/org/python/expose/generate/ExposedMethodFinder.java b/src/org/python/expose/generate/ExposedMethodFinder.java index 0c3d90c1d..9c88c0ba6 100644 --- a/src/org/python/expose/generate/ExposedMethodFinder.java +++ b/src/org/python/expose/generate/ExposedMethodFinder.java @@ -35,7 +35,7 @@ public ExposedMethodFinder(String typeName, String desc, String[] exceptions, MethodVisitor delegate) { - super(Opcodes.ASM5, delegate); + super(Opcodes.ASM7, delegate); this.typeName = typeName; this.onType = onType; this.access = access; diff --git a/src/org/python/expose/generate/ExposedTypeProcessor.java b/src/org/python/expose/generate/ExposedTypeProcessor.java index 5d143197f..5bdf19a4a 100644 --- a/src/org/python/expose/generate/ExposedTypeProcessor.java +++ b/src/org/python/expose/generate/ExposedTypeProcessor.java @@ -114,7 +114,7 @@ private final class TypeProcessor extends ClassVisitor { private boolean generatedStaticBlock; private TypeProcessor(ClassVisitor cv) { - super(Opcodes.ASM5, cv); + super(Opcodes.ASM7, cv); } @Override @@ -228,7 +228,7 @@ public MethodVisitor visitMethod(int access, desc, signature, exceptions); - return new MethodVisitor(Opcodes.ASM5, passthroughVisitor) { + return new MethodVisitor(Opcodes.ASM7, passthroughVisitor) { @Override public void visitCode() { diff --git a/src/org/python/expose/generate/ExposedTypeVisitor.java b/src/org/python/expose/generate/ExposedTypeVisitor.java index bc80133e4..bf10d1aa8 100644 --- a/src/org/python/expose/generate/ExposedTypeVisitor.java +++ b/src/org/python/expose/generate/ExposedTypeVisitor.java @@ -57,9 +57,9 @@ public void visitEnd() { /** * @param name the name the type should be exposed as from the annotation - * @param name the specified base type - * @param name the value of the isBaseType flag - * @param name the type's docstring + * @param base the specified base type + * @param isBaseType the value of the isBaseType flag + * @param doc the type's docstring */ public abstract void handleResult(String name, Type base, boolean isBaseType, String doc); } diff --git a/src/org/python/expose/generate/Exposer.java b/src/org/python/expose/generate/Exposer.java index 42c343d56..3f0eb9f35 100644 --- a/src/org/python/expose/generate/Exposer.java +++ b/src/org/python/expose/generate/Exposer.java @@ -53,7 +53,7 @@ public abstract class Exposer implements Opcodes, PyTypes { * @param generatedName - * the name of the class to generate */ - public Exposer(Class superClass, String generatedName, Type...interfacesImplemented) { + public Exposer(Class superClass, String generatedName, Type...interfacesImplemented) { superType = Type.getType(superClass); thisType = Type.getType("L" + generatedName.replace('.', '/') + ";"); this.interfacesImplemented = interfacesImplemented; diff --git a/src/org/python/expose/generate/MethodExposer.java b/src/org/python/expose/generate/MethodExposer.java index d139b27dd..4189844b7 100644 --- a/src/org/python/expose/generate/MethodExposer.java +++ b/src/org/python/expose/generate/MethodExposer.java @@ -25,7 +25,7 @@ public MethodExposer(Type onType, String typeName, String[] asNames, String[] defaults, - Class superClass, + Class superClass, String doc) { super(superClass, onType.getClassName() + "$" + methodName + "_exposer"); this.onType = onType; @@ -249,26 +249,26 @@ private void pushDefault(String def, Type arg) { // For primitive types, parse using the Java wrapper for that type and push onto the // stack as a constant. If the default is malformed, a NumberFormatException will be // raised. - mv.visitLdcInsn(new Long(def)); + mv.visitLdcInsn(Long.valueOf(def)); } else if(arg.equals(INT)) { - mv.visitLdcInsn(new Integer(def)); + mv.visitLdcInsn(Integer.valueOf(def)); } else if(arg.equals(BYTE)) { // byte, char, boolean and short go as int constants onto the stack, so convert them // to ints to get the right type - mv.visitLdcInsn(new Byte(def).intValue()); + mv.visitLdcInsn(Byte.valueOf(def).intValue()); } else if(arg.equals(SHORT)) { - mv.visitLdcInsn(new Short(def).intValue()); + mv.visitLdcInsn(Short.valueOf(def).intValue()); } else if(arg.equals(CHAR)) { if(def.length() != 1) { throwInvalid("A default for a char argument must be one character in length"); } - mv.visitLdcInsn((int)new Character(def.charAt(0)).charValue()); + mv.visitLdcInsn(def.charAt(0)); } else if(arg.equals(BOOLEAN)) { mv.visitLdcInsn(Boolean.valueOf(def) ? 1 : 0); } else if(arg.equals(Type.FLOAT_TYPE)) { - mv.visitLdcInsn(new Float(def)); + mv.visitLdcInsn(Float.valueOf(def)); } else if(arg.equals(Type.DOUBLE_TYPE)) { - mv.visitLdcInsn(new Double(def)); + mv.visitLdcInsn(Double.valueOf(def)); } } diff --git a/src/org/python/expose/generate/NewExposer.java b/src/org/python/expose/generate/NewExposer.java index 6cb58e3a7..095d11e9a 100644 --- a/src/org/python/expose/generate/NewExposer.java +++ b/src/org/python/expose/generate/NewExposer.java @@ -50,7 +50,7 @@ private void generateNewImpl() { mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 4); - mv.visitMethodInsn(INVOKESTATIC, onType.getInternalName(), name, NEW_DESCRIPTOR); + mv.visitMethodInsn(INVOKESTATIC, onType.getInternalName(), name, NEW_DESCRIPTOR, false); endMethod(ARETURN); } diff --git a/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java b/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java index 6ca10d713..a354b5aa2 100644 --- a/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java +++ b/src/org/python/expose/generate/RestrictiveAnnotationVisitor.java @@ -10,7 +10,7 @@ public class RestrictiveAnnotationVisitor extends AnnotationVisitor { public RestrictiveAnnotationVisitor() { - super(Opcodes.ASM5); + super(Opcodes.ASM7); } public AnnotationVisitor visitAnnotation(String name, String desc) { diff --git a/src/org/python/expose/generate/TypeExposer.java b/src/org/python/expose/generate/TypeExposer.java index 2efc14515..a780de5d3 100644 --- a/src/org/python/expose/generate/TypeExposer.java +++ b/src/org/python/expose/generate/TypeExposer.java @@ -88,9 +88,9 @@ public TypeBuilder makeBuilder() { for(MethodExposer me : methods) { me.load(l); } - Class descriptor = load(l); + Class descriptor = load(l); try { - return (TypeBuilder)descriptor.newInstance(); + return (TypeBuilder)descriptor.getDeclaredConstructor().newInstance(); } catch(Exception e) { // If we're unable to create the generated class, the process is // definitely ill, but that shouldn't be the case most of the time diff --git a/src/org/python/indexer/Indexer.java b/src/org/python/indexer/Indexer.java index f6ea10d0f..93f3da529 100644 --- a/src/org/python/indexer/Indexer.java +++ b/src/org/python/indexer/Indexer.java @@ -7,6 +7,7 @@ import org.python.indexer.ast.NNode; import org.python.indexer.ast.NModule; import org.python.indexer.ast.NName; +import org.python.indexer.ast.NStr; import org.python.indexer.ast.NUrl; import org.python.indexer.types.NModuleType; import org.python.indexer.types.NType; @@ -159,7 +160,7 @@ public boolean aggressiveAssertionsEnabled() { } /** - * If aggressive assertions are enabled, propages the passed + * If aggressive assertions are enabled, propagates the passed * {@link Throwable}, wrapped in an {@link IndexingException}. * @param msg descriptive message; ok to be {@code null} * @throws IndexingException @@ -193,7 +194,7 @@ public void handleException(String msg, Throwable cause) { * If aggressive assertions are enabled, throws an {@code IndexingException}. * Otherwise the message is logged as a warning, and indexing continues. * @param msg a descriptive message about the problem - * @see enableAggressiveAssertions + * @see #enableAggressiveAssertions(boolean) * @throws IndexingException */ public void reportFailedAssertion(String msg) { @@ -233,7 +234,7 @@ public void setPath(List path) throws IOException { /** * Returns the module search path -- the project directory followed by any - * paths that were added by {@link addPath}. + * paths that were added by {@link #addPath(String)}. */ public List getLoadPath() { List loadPath = new ArrayList(); @@ -321,8 +322,8 @@ public List getDiagnosticsForFile(String file) { * @return a list of entries constituting the file outline. * Returns an empty list if the indexer hasn't indexed that path. */ - public List generateOutline(String file) throws Exception { - return new Outliner().generate(this, file); + public List generateOutline(String path) throws Exception { + return new Outliner().generate(this, path); } /** @@ -508,7 +509,7 @@ public NModuleType loadString(String path, String contents) throws Exception { * If it is a directory, it is suffixed with "__init__.py", and * only that file is loaded from the directory. * - * @param noparents {@code true} to skip loading ancestor packages + * @param skipChain {@code true} to skip loading ancestor packages * * @return {@code null} if {@code path} could not be loaded */ @@ -650,18 +651,19 @@ public NModuleType getBuiltinModule(String qname) throws Exception { } /** - * This method searches the module path for the module {@code modname}. - * If found, it is passed to {@link #loadFile}. + * This method searches the module path for the module {@code modname}. If found, it is passed + * to {@link #loadFile}. * - *

    The mechanisms for importing modules are in general statically - * undecidable. We make a reasonable effort to follow the most common - * lookup rules. + *

    + * The mechanisms for importing modules are in general statically undecidable. We make a + * reasonable effort to follow the most common lookup rules. * - * @param modname a module name. Can be a relative path to a directory - * or a file (without the extension) or a possibly-qualified - * module name. If it is a module name, cannot contain leading dots. + * @param modname a module name. Can be a relative path to a directory or a file (without the + * extension) or a possibly-qualified module name. If it is a module name, cannot + * contain leading dots. * - * @see http://docs.python.org/reference/simple_stmts.html#the-import-statement + * @see The + * Import Statement */ public NModuleType loadModule(String modname) throws Exception { if (failedModules.contains(modname)) { diff --git a/src/org/python/indexer/IndexingException.java b/src/org/python/indexer/IndexingException.java index fa32620da..de037a9ec 100644 --- a/src/org/python/indexer/IndexingException.java +++ b/src/org/python/indexer/IndexingException.java @@ -6,7 +6,8 @@ /** * Signals that indexing is being aborted. - * @see {Indexer#enableAggressiveAssertions} + * + * @see Indexer#enableAggressiveAssertions(boolean) */ public class IndexingException extends RuntimeException { diff --git a/src/org/python/indexer/NBinding.java b/src/org/python/indexer/NBinding.java index cfd367563..7b47794b2 100644 --- a/src/org/python/indexer/NBinding.java +++ b/src/org/python/indexer/NBinding.java @@ -8,6 +8,7 @@ import org.python.indexer.ast.NUrl; import org.python.indexer.types.NModuleType; import org.python.indexer.types.NType; +import org.python.indexer.types.NUnionType; import org.python.indexer.types.NUnknownType; import java.util.ArrayList; @@ -17,15 +18,13 @@ import java.util.Set; /** - * An {@code NBinding} collects information about a fully qualified name (qname) - * in the code graph.

    - * - * Each qname has an associated {@link NType}. When a particular qname is - * assigned values of different types at different locations, its type is - * represented as a {@link NUnionType}.

    - * - * Each qname has a set of one or more definitions, and a set of zero or - * more references. Definitions and references correspond to code locations.

    + * An {@code NBinding} collects information about a fully qualified name (qname) in the code graph. + *

    + * Each qname has an associated {@link NType}. When a particular qname is assigned values of + * different types at different locations, its type is represented as a {@link NUnionType}. + *

    + * Each qname has a set of one or more definitions, and a set of zero or more references. + * Definitions and references correspond to code locations. */ public class NBinding implements Comparable { @@ -256,6 +255,7 @@ public boolean isProvisional() { /** * Bindings can be sorted by their location for outlining purposes. */ + @Override public int compareTo(Object o) { return getSignatureNode().start() - ((NBinding)o).getSignatureNode().start(); } diff --git a/src/org/python/indexer/Outliner.java b/src/org/python/indexer/Outliner.java index 1f0e7820b..1cddf06f2 100644 --- a/src/org/python/indexer/Outliner.java +++ b/src/org/python/indexer/Outliner.java @@ -121,18 +121,23 @@ public Branch() { public Branch(String qname, int start, NBinding.Kind kind) { super(qname, start, kind); } + @Override public boolean isLeaf() { return false; } + @Override public boolean isBranch() { return true; } + @Override public boolean hasChildren() { return children != null && !children.isEmpty(); } + @Override public List getChildren() { return children; } + @Override public void setChildren(List children) { this.children = children; } @@ -142,9 +147,11 @@ public void setChildren(List children) { * An entry with no children. */ public static class Leaf extends Entry { + @Override public boolean isLeaf() { return true; } + @Override public boolean isBranch() { return false; } @@ -155,12 +162,15 @@ public Leaf() { public Leaf(String qname, int start, NBinding.Kind kind) { super(qname, start, kind); } + @Override public boolean hasChildren() { return false; } + @Override public List getChildren() { return new ArrayList(); } + @Override public void setChildren(List children) { throw new UnsupportedOperationException("Leaf nodes cannot have children."); } @@ -168,8 +178,8 @@ public void setChildren(List children) { /** * Create an outline for a file in the index. - * @param scope the file scope - * @param path the file for which to build the outline + * @param idx index holding the file scope + * @param abspath the file for which to build the outline * @return a list of entries constituting the file outline. * Returns an empty list if the indexer hasn't indexed that path. */ diff --git a/src/org/python/indexer/Scope.java b/src/org/python/indexer/Scope.java index 50b5dc637..ce531c005 100644 --- a/src/org/python/indexer/Scope.java +++ b/src/org/python/indexer/Scope.java @@ -148,10 +148,10 @@ public boolean isGlobalName(String name) { /** * Directly assigns a binding to a name in this table. Does not add a new * definition or reference to the binding. This form of {@code put} is - * often followed by a call to {@link putLocation} to create a reference to + * often followed by a call to {@link Indexer#putLocation} to create a reference to * the binding. When there is no code location associated with {@code id}, * or it is otherwise undesirable to create a reference, the - * {@link putLocation} call is omitted. + * {@link Indexer#putLocation} call is omitted. */ public void put(String id, NBinding b) { putBinding(id, b); @@ -482,7 +482,7 @@ public NBinding lookupAttr(String name, boolean supersOnly) { /** * Look up an attribute in the local scope and superclass scopes. - * @see lookupAttr(String,boolean) + * @see #lookupAttr(String,boolean) */ public NBinding lookupAttr(String name) { return lookupAttr(name, false); diff --git a/src/org/python/indexer/ast/DefaultNodeVisitor.java b/src/org/python/indexer/ast/DefaultNodeVisitor.java index 85fe30987..89032ec49 100644 --- a/src/org/python/indexer/ast/DefaultNodeVisitor.java +++ b/src/org/python/indexer/ast/DefaultNodeVisitor.java @@ -20,224 +20,278 @@ public class DefaultNodeVisitor implements NNodeVisitor { * and then tree traversal halts.

    * * If the traversal should be halted immediately without visiting any further - * nodes, the visitor can throw a {@link StopIterationException}. + * nodes, the visitor can throw a {@link NNodeVisitor.StopIterationException}. */ public void stopTraversal() { traverseIntoNodes = false; } + @Override public boolean visit(NAlias n) { return traverseIntoNodes; } + @Override public boolean visit(NAssert n) { return traverseIntoNodes; } + @Override public boolean visit(NAssign n) { return traverseIntoNodes; } + @Override public boolean visit(NAttribute n) { return traverseIntoNodes; } + @Override public boolean visit(NAugAssign n) { return traverseIntoNodes; } + @Override public boolean visit(NBinOp n) { return traverseIntoNodes; } + @Override public boolean visit(NBlock n) { return traverseIntoNodes; } + @Override public boolean visit(NBoolOp n) { return traverseIntoNodes; } + @Override public boolean visit(NBreak n) { return traverseIntoNodes; } + @Override public boolean visit(NCall n) { return traverseIntoNodes; } + @Override public boolean visit(NClassDef n) { return traverseIntoNodes; } + @Override public boolean visit(NCompare n) { return traverseIntoNodes; } + @Override public boolean visit(NComprehension n) { return traverseIntoNodes; } + @Override public boolean visit(NContinue n) { return traverseIntoNodes; } + @Override public boolean visit(NDelete n) { return traverseIntoNodes; } + @Override public boolean visit(NDict n) { return traverseIntoNodes; } + @Override public boolean visit(NEllipsis n) { return traverseIntoNodes; } + @Override public boolean visit(NExceptHandler n) { return traverseIntoNodes; } + @Override public boolean visit(NExec n) { return traverseIntoNodes; } + @Override public boolean visit(NFor n) { return traverseIntoNodes; } + @Override public boolean visit(NFunctionDef n) { return traverseIntoNodes; } + @Override public boolean visit(NGeneratorExp n) { return traverseIntoNodes; } + @Override public boolean visit(NGlobal n) { return traverseIntoNodes; } + @Override public boolean visit(NIf n) { return traverseIntoNodes; } + @Override public boolean visit(NIfExp n) { return traverseIntoNodes; } + @Override public boolean visit(NImport n) { return traverseIntoNodes; } + @Override public boolean visit(NImportFrom n) { return traverseIntoNodes; } + @Override public boolean visit(NIndex n) { return traverseIntoNodes; } + @Override public boolean visit(NKeyword n) { return traverseIntoNodes; } + @Override public boolean visit(NLambda n) { return traverseIntoNodes; } + @Override public boolean visit(NList n) { return traverseIntoNodes; } + @Override public boolean visit(NListComp n) { return traverseIntoNodes; } + @Override public boolean visit(NModule n) { return traverseIntoNodes; } + @Override public boolean visit(NName n) { return traverseIntoNodes; } + @Override public boolean visit(NNum n) { return traverseIntoNodes; } + @Override public boolean visit(NPass n) { return traverseIntoNodes; } + @Override public boolean visit(NPlaceHolder n) { return traverseIntoNodes; } + @Override public boolean visit(NPrint n) { return traverseIntoNodes; } + @Override public boolean visit(NQname n) { return traverseIntoNodes; } + @Override public boolean visit(NRaise n) { return traverseIntoNodes; } + @Override public boolean visit(NRepr n) { return traverseIntoNodes; } + @Override public boolean visit(NReturn n) { return traverseIntoNodes; } + @Override public boolean visit(NExprStmt n) { return traverseIntoNodes; } + @Override public boolean visit(NSlice n) { return traverseIntoNodes; } + @Override public boolean visit(NStr n) { return traverseIntoNodes; } + @Override public boolean visit(NSubscript n) { return traverseIntoNodes; } + @Override public boolean visit(NTryExcept n) { return traverseIntoNodes; } + @Override public boolean visit(NTryFinally n) { return traverseIntoNodes; } + @Override public boolean visit(NTuple n) { return traverseIntoNodes; } + @Override public boolean visit(NUnaryOp n) { return traverseIntoNodes; } + @Override public boolean visit(NUrl n) { return traverseIntoNodes; } + @Override public boolean visit(NWhile n) { return traverseIntoNodes; } + @Override public boolean visit(NWith n) { return traverseIntoNodes; } + @Override public boolean visit(NYield n) { return traverseIntoNodes; } diff --git a/src/org/python/indexer/ast/NNode.java b/src/org/python/indexer/ast/NNode.java index 19be33480..0b67008d9 100644 --- a/src/org/python/indexer/ast/NNode.java +++ b/src/org/python/indexer/ast/NNode.java @@ -85,7 +85,7 @@ public Scope getTable() { /** * Returns the type for this node. It is never {@code null}. * If the node has not been resolved, the type will default to - * {@link Indexer.idx.builtins.None}. + * {@code Indexer.idx.builtins.None}. */ public NType getType() { if (type == null) { @@ -122,11 +122,11 @@ public NType addType(NType newType) { } /** - * Returns {@code true} if this is a name-binding node. - * Includes functions/lambdas, function/lambda params, classes, - * assignments, imports, and implicit assignment via for statements - * and except clauses. - * @see http://www.python.org/dev/peps/pep-0227 + * Returns {@code true} if this is a name-binding node. Includes functions/lambdas, + * function/lambda params, classes, assignments, imports, and implicit assignment via for + * statements and except clauses. + * + * @see PEP 227 */ public boolean bindsName() { return false; @@ -350,6 +350,7 @@ public NNode getNode() { return deepest; } + @Override public boolean dispatch(NNode node) { // This node ends before the offset, so don't look inside it. if (offset > node.end) { diff --git a/src/org/python/indexer/demos/Styler.java b/src/org/python/indexer/demos/Styler.java index 27977db3d..e67c56d49 100644 --- a/src/org/python/indexer/demos/Styler.java +++ b/src/org/python/indexer/demos/Styler.java @@ -151,7 +151,7 @@ public void reportError(BaseRecognizer br, RecognitionException re) { }); Token tok; - while ((tok = lex.nextToken()) != Token.EOF_TOKEN) { + while ((tok = lex.nextToken()).getType() != Token.EOF) { switch (tok.getType()) { case PythonLexer.STRING: { int beg = ((CommonToken)tok).getStartIndex(); diff --git a/src/org/python/indexer/types/NUnionType.java b/src/org/python/indexer/types/NUnionType.java index 66aba43a9..734fa2c70 100644 --- a/src/org/python/indexer/types/NUnionType.java +++ b/src/org/python/indexer/types/NUnionType.java @@ -17,11 +17,12 @@ public class NUnionType extends NType { /** - * Union types can lead to infinite recursion in the occurs check. Until - * we've got a handle on these cases, I'm limiting the recursion depth. + * Union types can lead to infinite recursion in the occurs check. Until we've got a handle on + * these cases, I'm limiting the recursion depth. * - * @see http://www.cs.kuleuven.ac.be/~dtai/projects/ALP/newsletter/archive_93_96/net/impl/occur.html - * for an interesting and highly relevant discussion. + * @see + * The Occurs Check for an interesting and highly relevant discussion. */ private static final int MAX_RECURSION_DEPTH = 15; @@ -133,7 +134,7 @@ public static NType union(NType u, NType v) { } /** - * @see http://en.wikipedia.org/wiki/Occurs_check + * @see Occurs check */ private static boolean occurs(NType u, NType v, int depth) { if (depth++ > MAX_RECURSION_DEPTH) { @@ -210,7 +211,7 @@ public NType firstKnownAlternate() { /** * Returns the first alternate whose type is not unknown and - * is not {@link Indexer.idx.builtins.None}. + * is not {@code Indexer#idx.builtins.None}. * @return the first non-unknown, non-{@code None} alternate, or {@code null} if none found */ public NType firstKnownNonNullAlternate() { diff --git a/src/org/python/modules/PyStructDerived.java b/src/org/python/modules/PyStructDerived.java index 0726d9bc6..664829f08 100644 --- a/src/org/python/modules/PyStructDerived.java +++ b/src/org/python/modules/PyStructDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/Setup.java b/src/org/python/modules/Setup.java index 45812d668..24af6b186 100644 --- a/src/org/python/modules/Setup.java +++ b/src/org/python/modules/Setup.java @@ -41,7 +41,6 @@ public class Setup "_py_compile", "_random:org.python.modules.random.RandomModule", "_sre", - "_systemrestart", "_threading:org.python.modules._threading._threading", "_weakref:org.python.modules._weakref.WeakrefModule", "array:org.python.modules.ArrayModule", @@ -57,6 +56,7 @@ public class Setup "itertools:org.python.modules.itertools.itertools", "jarray", "jffi:org.python.modules.jffi.jffi", + "_locale:org.python.modules._locale._locale", "math", "operator", "struct", diff --git a/src/org/python/modules/_bytecodetools.java b/src/org/python/modules/_bytecodetools.java index b212b48dd..630f7b06a 100644 --- a/src/org/python/modules/_bytecodetools.java +++ b/src/org/python/modules/_bytecodetools.java @@ -6,7 +6,7 @@ /** * BytecodeTools provides tools for generated JVM bytecode. - *

    + *

    * This module supports registering a python callback function * to be notified when new bytecode is loaded. * see also core/BytecodeNotification.java diff --git a/src/org/python/modules/_collections/PyDefaultDict.java b/src/org/python/modules/_collections/PyDefaultDict.java index 879241553..5dcebaea3 100644 --- a/src/org/python/modules/_collections/PyDefaultDict.java +++ b/src/org/python/modules/_collections/PyDefaultDict.java @@ -7,8 +7,10 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import org.python.core.BuiltinDocs; import org.python.core.Py; import org.python.core.PyDictionary; +import org.python.core.PyException; import org.python.core.PyObject; import org.python.core.PyTuple; import org.python.core.PyType; @@ -21,11 +23,6 @@ import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -import com.google.common.collect.MapMaker; -import com.google.common.collect.ComputationException; -import com.google.common.base.Function; -import org.python.core.BuiltinDocs; - /** * PyDefaultDict - This is a subclass of the builtin dict(PyDictionary) class. It supports * one additional method __missing__ and adds one writable instance variable @@ -60,7 +57,11 @@ public PyDefaultDict(PyType subtype) { backingMap = CacheBuilder.newBuilder().build( new CacheLoader() { public PyObject load(PyObject key) { - return __missing__(key); + try { + return __missing__(key); + } catch (RuntimeException ex) { + throw new MissingThrownException(ex); + } } }); } @@ -165,7 +166,18 @@ public PyObject __finditem__(PyObject key) { protected final PyObject defaultdict___getitem__(PyObject key) { try { return backingMap.get(key); + } catch (PyException pe) { + /* LoadingCache#get() don't throw any PyException itself and it + * prevents those raised in CacheLoader#load() to get through + * without being wrapped in UncheckedExecutionException, so this + * PyException must be from key#hashCode(). We can propagated it to + * caller as it is. */ + throw pe; } catch (Exception ex) { + Throwable cause = ex.getCause(); + if (cause != null && cause instanceof MissingThrownException) { + throw ((MissingThrownException) cause).thrownByMissing; + } throw Py.KeyError(key); } } @@ -220,4 +232,12 @@ public boolean refersDirectlyTo(PyObject ob) { } return backingMap.asMap().containsKey(ob) || backingMap.asMap().containsValue(ob); } + + private static class MissingThrownException extends RuntimeException { + final RuntimeException thrownByMissing; + MissingThrownException(RuntimeException thrownByMissing) { + super(thrownByMissing); + this.thrownByMissing = thrownByMissing; + } + } } diff --git a/src/org/python/modules/_collections/PyDefaultDictDerived.java b/src/org/python/modules/_collections/PyDefaultDictDerived.java index 9c5384934..e534216b9 100644 --- a/src/org/python/modules/_collections/PyDefaultDictDerived.java +++ b/src/org/python/modules/_collections/PyDefaultDictDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/_collections/PyDequeDerived.java b/src/org/python/modules/_collections/PyDequeDerived.java index c0b956b41..4901a6251 100644 --- a/src/org/python/modules/_collections/PyDequeDerived.java +++ b/src/org/python/modules/_collections/PyDequeDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/_csv/PyDialect.java b/src/org/python/modules/_csv/PyDialect.java index b702842e0..537bfb57a 100644 --- a/src/org/python/modules/_csv/PyDialect.java +++ b/src/org/python/modules/_csv/PyDialect.java @@ -1,4 +1,4 @@ -/* Copyright (c) Jython Developers */ +/* Copyright (c)2017 Jython Developers */ package org.python.modules._csv; import org.python.core.ArgParser; @@ -9,6 +9,7 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyType; +import org.python.core.PyUnicode; import org.python.core.Untraversable; import org.python.expose.ExposedDelete; import org.python.expose.ExposedGet; @@ -153,17 +154,21 @@ private static boolean toBool(String name, PyObject src, boolean dflt) { private static char toChar(String name, PyObject src, char dflt) { if (src == null) { return dflt; - } - boolean isStr = Py.isInstance(src, PyString.TYPE); - if (src == Py.None || isStr && src.__len__() == 0) { + } else if (src == Py.None) { return '\0'; - } else if (!isStr || src.__len__() != 1) { - throw Py.TypeError(String.format("\"%s\" must be an 1-character string", name)); - } - return src.toString().charAt(0); + } else if (src instanceof PyString) { + String s = (src instanceof PyUnicode) ? ((PyUnicode) src).encode() : src.toString(); + if (s.length() == 0) { + return '\0'; + } else if (s.length() == 1) { + return s.charAt(0); + } + } + // This is only going to work for BMP strings because of the char return type + throw Py.TypeError(String.format("\"%s\" must be a 1-character string", name)); } - private static int toInt(String name, PyObject src, int dflt) { + private static int toInt(String name, PyObject src, int dflt) { if (src == null) { return dflt; } @@ -176,14 +181,14 @@ private static int toInt(String name, PyObject src, int dflt) { private static String toStr(String name, PyObject src, String dflt) { if (src == null) { return dflt; - } - if (src == Py.None) { + } else if (src == Py.None) { return null; + } else if (src instanceof PyUnicode) { + return ((PyUnicode) src).encode().toString(); + } else if (src instanceof PyString) { + return src.toString(); } - if (!(src instanceof PyBaseString)) { - throw Py.TypeError(String.format("\"%s\" must be an string", name)); - } - return src.toString(); + throw Py.TypeError(String.format("\"%s\" must be a string", name)); } @ExposedGet(name = "escapechar") diff --git a/src/org/python/modules/_csv/PyWriter.java b/src/org/python/modules/_csv/PyWriter.java index 3943a47a2..1156b672d 100644 --- a/src/org/python/modules/_csv/PyWriter.java +++ b/src/org/python/modules/_csv/PyWriter.java @@ -1,4 +1,4 @@ -/* Copyright (c) Jython Developers */ +/* Copyright (c)2017 Jython Developers */ package org.python.modules._csv; import org.python.core.Py; @@ -7,6 +7,7 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyType; +import org.python.core.PyUnicode; import org.python.core.Traverseproc; import org.python.core.Visitproc; import org.python.expose.ExposedType; @@ -21,11 +22,9 @@ @ExposedType(name = "_csv.writer", doc = PyWriter.writer_doc) public class PyWriter extends PyObject implements Traverseproc { - public static final String writer_doc = - "CSV writer\n" + - "\n" + - "Writer objects are responsible for generating tabular data\n" + - "in CSV format from sequence input.\n"; + public static final String writer_doc = "CSV writer\n\n"// + + "Writer objects are responsible for generating tabular data\n" + + "in CSV format from sequence input.\n"; public static final PyType TYPE = PyType.fromClass(PyWriter.class); @@ -53,11 +52,10 @@ public PyWriter(PyObject writeline, PyDialect dialect) { this.dialect = dialect; } - public static PyString __doc__writerows = Py.newString( - "writerows(sequence of sequences)\n" + - "\n" + - "Construct and write a series of sequences to a csv file. Non-string\n" + - "elements will be converted to string."); + public static PyString __doc__writerows = Py.newString(// + "writerows(sequence of sequences)\n\n" + + "Construct and write a series of sequences to a csv file. Non-string\n" + + "elements will be converted to string."); public void writerows(PyObject seqseq) { writer_writerows(seqseq); @@ -82,12 +80,10 @@ final void writer_writerows(PyObject seqseq) { } } - public static PyString __doc__writerow = Py.newString( - "writerow(sequence)\n" + - "\n" + - "Construct and write a CSV record from a sequence of fields. Non-string\n" + - "elements will be converted to string." - ); + public static PyString __doc__writerow = Py.newString(// + "writerow(sequence)\n\n" + + "Construct and write a CSV record from a sequence of fields. Non-string\n" + + "elements will be converted to string."); public boolean writerow(PyObject seq) { return writer_writerow(seq); @@ -134,14 +130,17 @@ final boolean writer_writerow(PyObject seq) { quoted = false; } - if (field instanceof PyString) { + if (field instanceof PyUnicode) { + // Unicode fields get the default encoding (must yield U16 bytes). + append_ok = join_append(((PyString) field).encode(), len == 1); + } else if (field instanceof PyString) { + // Not unicode, so must be U16 bytes. append_ok = join_append(field.toString(), len == 1); } else if (field == Py.None) { append_ok = join_append("", len == 1); } else { PyObject str; - //XXX: in 3.x this check can go away and we can just always use - // __str__ + // XXX: in 3.x this check can go away and we can just always use __str__ if (field.getClass() == PyFloat.class) { str = field.__repr__(); } else { @@ -195,9 +194,9 @@ private boolean join_append(String field, boolean quote_empty) { } /** - * This method behaves differently depending on the value of copy_phase: if copy_phase - * is false, then the method determines the new record length. If copy_phase is true - * then the new field is appended to the record. + * This method behaves differently depending on the value of copy_phase: if copy_phase is false, + * then the method determines the new record length. If copy_phase is true then the new field is + * appended to the record. */ private int join_append_data(String field, boolean quote_empty, boolean copy_phase) { int i; @@ -225,7 +224,7 @@ private int join_append_data(String field, boolean quote_empty, boolean copy_pha break; } if (c == dialect.delimiter || c == dialect.escapechar || c == dialect.quotechar - || dialect.lineterminator.indexOf(c) > -1) { + || dialect.lineterminator.indexOf(c) > -1) { if (dialect.quoting == QuoteStyle.QUOTE_NONE) { want_escape = true; } else { @@ -282,7 +281,6 @@ private void addChar(char c, boolean copy_phase) { rec_len++; } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { diff --git a/src/org/python/modules/_functools/PyPartial.java b/src/org/python/modules/_functools/PyPartial.java index be1a67012..f22f419ba 100644 --- a/src/org/python/modules/_functools/PyPartial.java +++ b/src/org/python/modules/_functools/PyPartial.java @@ -8,6 +8,7 @@ import org.python.core.PyNewWrapper; import org.python.core.PyObject; import org.python.core.PyStringMap; +import org.python.core.AbstractDict; import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.Traverseproc; @@ -176,7 +177,7 @@ public PyObject getDict() { @Override @ExposedSet(name = "__dict__") public void setDict(PyObject val) { - if (!(val instanceof PyStringMap) && !(val instanceof PyDictionary)) { + if (!(val instanceof AbstractDict)) { throw Py.TypeError("setting partial object's dictionary to a non-dict"); } __dict__ = val; diff --git a/src/org/python/modules/_functools/PyPartialDerived.java b/src/org/python/modules/_functools/PyPartialDerived.java index 02a75bbb6..a18b8a1d0 100644 --- a/src/org/python/modules/_functools/PyPartialDerived.java +++ b/src/org/python/modules/_functools/PyPartialDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/_hashlib.java b/src/org/python/modules/_hashlib.java index 9fbb22779..dfbaeb79d 100644 --- a/src/org/python/modules/_hashlib.java +++ b/src/org/python/modules/_hashlib.java @@ -9,8 +9,10 @@ import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyArray; +import org.python.core.PyFrozenSet; import org.python.core.PyObject; import org.python.core.PyString; +import org.python.core.PyTuple; import org.python.core.PyType; import org.python.core.PyUnicode; import org.python.core.Untraversable; @@ -37,6 +39,11 @@ public class _hashlib implements ClassDictInit { put("sha512", "sha-512"); }}; + public static final PyFrozenSet openssl_md_meth_names = + new PyFrozenSet(new PyTuple(Py.newString("md5"), Py.newString("sha1"), + Py.newString("sha224"), Py.newString("sha256"), Py.newString("sha384"), + Py.newString("sha512"))); + public static void classDictInit(PyObject dict) { dict.__setitem__("__name__", Py.newString("_hashlib")); dict.__setitem__("algorithmMap", null); diff --git a/src/org/python/modules/_imp.java b/src/org/python/modules/_imp.java index 868a85db4..e04dbf0cb 100644 --- a/src/org/python/modules/_imp.java +++ b/src/org/python/modules/_imp.java @@ -1,7 +1,13 @@ package org.python.modules; -import org.python.core.__builtin__; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + import org.python.core.Py; import org.python.core.PyFile; import org.python.core.PyList; @@ -10,10 +16,8 @@ import org.python.core.PyString; import org.python.core.PySystemState; import org.python.core.PyTuple; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import org.python.core.__builtin__; +import org.python.core.imp; /* * A bogus implementation of the CPython builtin module "imp". @@ -36,6 +40,8 @@ public class _imp { public static final int PY_FROZEN = 7; public static final int IMP_HOOK = 9; + private static Logger logger = Logger.getLogger("org.python.import"); + private static class ModuleInfo { PyObject file; String filename; @@ -60,21 +66,21 @@ private static PyObject newFile(File file) { } private static boolean caseok(File file, String filename) { - return org.python.core.imp.caseok(file, filename); + return imp.caseok(file, filename); } /** * This needs to be consolidated with the code in (@see org.python.core.imp). * * @param name module name - * @param entry a path String + * @param entry a path String (Unicode file or directory name) * @param findingPackage if looking for a package only try to locate __init__ * @return null if no module found otherwise module information */ static ModuleInfo findFromSource(String name, String entry, boolean findingPackage, boolean preferSource) { String sourceName = "__init__.py"; - String compiledName = "__init__$py.class"; + String compiledName = imp.makeCompiledFilename(sourceName); String directoryName = PySystemState.getPathLazy(entry); // displayDirName is for identification purposes: when null it // forces java.io.File to be a relative path (e.g. foo/bar.py @@ -94,9 +100,9 @@ static ModuleInfo findFromSource(String name, String entry, boolean findingPacka return new ModuleInfo(Py.None, new File(displayDirName, name).getPath(), "", "", PKG_DIRECTORY); } else { - Py.writeDebug("import", "trying source " + dir.getPath()); + logger.log(Level.FINE, "# trying directory {0}", dir.getPath()); sourceName = name + ".py"; - compiledName = name + "$py.class"; + compiledName = imp.makeCompiledFilename(sourceName); sourceFile = new File(directoryName, sourceName); compiledFile = new File(directoryName, compiledName); } @@ -104,7 +110,7 @@ static ModuleInfo findFromSource(String name, String entry, boolean findingPacka if (sourceFile.isFile() && caseok(sourceFile, sourceName)) { if (!preferSource && compiledFile.isFile() && caseok(compiledFile, compiledName)) { - Py.writeDebug("import", "trying precompiled " + compiledFile.getPath()); + logger.log(Level.FINE, "# trying precompiled {0}", compiledFile.getPath()); long pyTime = sourceFile.lastModified(); long classTime = compiledFile.lastModified(); if (classTime >= pyTime) { @@ -119,7 +125,7 @@ static ModuleInfo findFromSource(String name, String entry, boolean findingPacka } // If no source, try loading precompiled - Py.writeDebug("import", "trying " + compiledFile.getPath()); + logger.log(Level.FINE, "# trying precompiled {0}", compiledFile.getPath()); if (compiledFile.isFile() && caseok(compiledFile, compiledName)) { return new ModuleInfo(newFile(compiledFile), new File(displayDirName, compiledName).getPath(), @@ -151,24 +157,46 @@ public static PyObject load_source(String modname, String filename, PyObject fil throw Py.TypeError("must be a file-like object"); } PySystemState sys = Py.getSystemState(); - String compiledFilename = - org.python.core.imp.makeCompiledFilename(sys.getPath(filename)); - mod = org.python.core.imp.createFromSource(modname.intern(), (InputStream)o, + String compiledFilename = imp.makeCompiledFilename(sys.getPath(filename)); + mod = imp.createFromSource(modname.intern(), (InputStream)o, filename, compiledFilename); PyObject modules = sys.modules; modules.__setitem__(modname.intern(), mod); return mod; } - public static PyObject load_compiled(String name, String pathname) { - return load_compiled(name, pathname, new PyFile(pathname, "rb", -1)); - } - public static PyObject reload(PyObject module) { return __builtin__.reload(module); } - public static PyObject load_compiled(String name, String pathname, PyObject file) { + /** + * Return a module with the given name, the result of executing the compiled code + * at the given pathname. If this path is a PyUnicode, it is used + * exactly; if it is a PyString it is taken to be file-system encoded. + * + * @param name the module name + * @param pathname to the compiled module (becomes __file__) + * @return the module called name + */ + public static PyObject load_compiled(String name, PyString pathname) { + String _pathname = Py.fileSystemDecode(pathname); + return _load_compiled(name, _pathname, new PyFile(_pathname, "rb", -1)); + } + + /** + * Return a module with the given name, the result of executing the compiled code + * in the given file stream. + * + * @param name the module name + * @param pathname a file path that is not null (becomes __file__) + * @param file stream from which the compiled code is taken + * @return the module called name + */ + public static PyObject load_compiled(String name, PyString pathname, PyObject file) { + return _load_compiled(name, Py.fileSystemDecode(pathname), file); + } + + private static PyObject _load_compiled(String name, String pathname, PyObject file) { InputStream stream = (InputStream) file.__tojava__(InputStream.class); if (stream == Py.NoConversion) { throw Py.TypeError("must be a file-like object"); @@ -180,7 +208,7 @@ public static PyObject load_compiled(String name, String pathname, PyObject file if (sourceName.endsWith("$py.class")) { sourceName = sourceName.substring(0, sourceName.length() - 9) + ".py"; } - return org.python.core.imp.loadFromCompiled(name.intern(), stream, sourceName, pathname); + return imp.loadFromCompiled(name.intern(), stream, sourceName, pathname); } public static PyObject find_module(String name) { @@ -189,8 +217,10 @@ public static PyObject find_module(String name) { public static PyObject find_module(String name, PyObject path) { if (path == Py.None && PySystemState.getBuiltin(name) != null) { - return new PyTuple(Py.None, Py.newString(name), - new PyTuple(Py.EmptyString, Py.EmptyString, + return new PyTuple(Py.None, + Py.newString(name), + new PyTuple(Py.EmptyString, + Py.EmptyString, Py.newInteger(C_BUILTIN))); } @@ -198,14 +228,15 @@ public static PyObject find_module(String name, PyObject path) { path = Py.getSystemState().path; } for (PyObject p : path.asIterable()) { - ModuleInfo mi = findFromSource(name, p.toString(), false, true); + ModuleInfo mi = findFromSource(name, Py.fileSystemDecode(p), false, true); if(mi == null) { continue; } return new PyTuple(mi.file, - new PyString(mi.filename), - new PyTuple(new PyString(mi.suffix), - new PyString(mi.mode), + // File names generally expected in the FS encoding + Py.fileSystemEncode(mi.filename), + new PyTuple(Py.newString(mi.suffix), + Py.newString(mi.mode), Py.newInteger(mi.type))); } throw Py.ImportError("No module named " + name); @@ -215,7 +246,8 @@ public static PyObject load_module(String name, PyObject file, PyObject filename PyObject mod = Py.None; PySystemState sys = Py.getSystemState(); int type = data.__getitem__(2).asInt(); - while(mod == Py.None) { + String filenameString = Py.fileSystemDecode(filename); + while (mod == Py.None) { String compiledName; switch (type) { case PY_SOURCE: @@ -225,8 +257,8 @@ public static PyObject load_module(String name, PyObject file, PyObject filename } // XXX: This should load the accompanying byte code file instead, if it exists - String resolvedFilename = sys.getPath(filename.toString()); - compiledName = org.python.core.imp.makeCompiledFilename(resolvedFilename); + String resolvedFilename = sys.getPath(filenameString); + compiledName = imp.makeCompiledFilename(resolvedFilename); if (name.endsWith(".__init__")) { name = name.substring(0, name.length() - ".__init__".length()); } else if (name.equals("__init__")) { @@ -239,23 +271,21 @@ public static PyObject load_module(String name, PyObject file, PyObject filename mtime = fp.lastModified(); } - mod = org.python.core.imp.createFromSource(name.intern(), - (InputStream)o, - filename.toString(), - compiledName, - mtime); + mod = imp.createFromSource(name.intern(), (InputStream)o, + filenameString, compiledName, mtime); break; case PY_COMPILED: - mod = load_compiled(name, filename.toString(), file); + mod = _load_compiled(name, filenameString, file); break; case PKG_DIRECTORY: - PyModule m = org.python.core.imp.addModule(name); + PyModule m = imp.addModule(name); m.__dict__.__setitem__("__path__", new PyList(new PyObject[] {filename})); m.__dict__.__setitem__("__file__", filename); - ModuleInfo mi = findFromSource(name, filename.toString(), true, true); + ModuleInfo mi = findFromSource(name, filenameString, true, true); type = mi.type; file = mi.file; - filename = new PyString(mi.filename); + filenameString = mi.filename; + filename = Py.newStringOrUnicode(filenameString); break; default: throw Py.ImportError("No module named " + name); @@ -266,10 +296,19 @@ public static PyObject load_module(String name, PyObject file, PyObject filename return mod; } + /** + * Variant of {@link imp#makeCompiledFilename(String)} dealing with encoded bytes. In the context + * where this is used from Python, a result in encoded bytes is preferable. + */ + public static PyString makeCompiledFilename(PyString filename) { + filename = Py.fileSystemEncode(filename); + return Py.newString(imp.makeCompiledFilename(filename.getString())); + } + public static PyObject get_magic() { - return new PyString("\u0003\u00f3\r\n"); + return new PyString("\u0003\u00f3\r\n"); } - + public static PyObject get_suffixes() { return new PyList(new PyObject[] {new PyTuple(new PyString(".py"), new PyString("r"), diff --git a/src/org/python/modules/_io/OpenMode.java b/src/org/python/modules/_io/OpenMode.java index 95985c283..368416367 100644 --- a/src/org/python/modules/_io/OpenMode.java +++ b/src/org/python/modules/_io/OpenMode.java @@ -120,10 +120,10 @@ public OpenMode(String mode) { *

    * The invalid combinations enforced here are those for the "raw" (ie non-text) file types: *

      - *
    • universal & (writing | appending)),
    • - *
    • text & binary
    • , - *
    • reading & writing,
    • - *
    • appending & (reading | writing)
    • + *
    • {@code universal & (writing | appending)},
    • + *
    • {@code text & binary},
    • + *
    • {@code reading & writing},
    • + *
    • {@code appending & (reading | writing)}
    • *
    * See also {@link #validate(String, String, String)} for additional checks relevant to text * files. @@ -191,7 +191,7 @@ public void validate(String encoding, String errors, String newline) { * by either {@link #invalid} or {@link #other} being true after that call. If no * more specific message has been assigned in {@link #message}, report the original mode string. * - * @throws PyException (ValueError) if the mode string was invalid. + * @throws PyException {@code ValueError} if the mode string was invalid. */ public void checkValid() throws PyException { diff --git a/src/org/python/modules/_io/PyFileIO.java b/src/org/python/modules/_io/PyFileIO.java index ae885b782..1aa494ca0 100644 --- a/src/org/python/modules/_io/PyFileIO.java +++ b/src/org/python/modules/_io/PyFileIO.java @@ -250,16 +250,11 @@ final PyLong FileIO_readinto(PyObject buf) { } else { // Perform the operation through a buffer view on the object - PyBuffer pybuf = writablePyBuffer(buf); - - try { + try (PyBuffer pybuf = writablePyBuffer(buf)) { ByteBuffer byteBuffer = pybuf.getNIOByteBuffer(); synchronized (ioDelegate) { count = ioDelegate.readinto(byteBuffer); } - } finally { - // Must unlock the PyBuffer view from client's object - pybuf.release(); } } @@ -290,17 +285,12 @@ final PyLong FileIO_write(PyObject buf) { } else { // Get or synthesise a buffer API on the object to be written - PyBuffer pybuf = readablePyBuffer(buf); - - try { + try (PyBuffer pybuf = readablePyBuffer(buf)) { // Access the data as a java.nio.ByteBuffer [pos:limit] within possibly larger array ByteBuffer byteBuffer = pybuf.getNIOByteBuffer(); synchronized (ioDelegate) { count = ioDelegate.write(byteBuffer); } - } finally { - // Even if that went badly, we should release the lock on the client buffer - pybuf.release(); } } @@ -370,15 +360,18 @@ public void close() { @ExposedMethod final synchronized void FileIO_close() { - // Close this object to further input (also calls flush) - super.close(); - // Now close downstream (if required to) - if (closefd) { - ioDelegate.close(); + try { + // Close this object to further input (also calls flush) + super.close(); + } finally { + // Now close downstream (if required to) + if (closefd) { + ioDelegate.close(); + } + // This saves us doing two tests for each action (when the file is open) + readable = false; + writable = false; } - // This saves us doing two tests for each action (when the file is open) - readable = false; - writable = false; } @Override diff --git a/src/org/python/modules/_io/PyIOBase.java b/src/org/python/modules/_io/PyIOBase.java index 00bd65b47..b66b17482 100644 --- a/src/org/python/modules/_io/PyIOBase.java +++ b/src/org/python/modules/_io/PyIOBase.java @@ -33,7 +33,7 @@ * Implementation note: The code is based heavily on the Jython 2.6-ish * _fileio.PyFileIO, the purely Java-accessible {@link org.python.core.io.IOBase} (both * Philip Jenvey's work), and the Python implementation in Lib/_pyio. We do not simply - * delegate to the implementation in {@link org.python.core.io} because of the need to override + * delegate to the implementation in {@code org.python.core.io} because of the need to override * parts of the implementation in Python subclasses. A call to {@link #close()}, for example, is * required to call {@link #flush()}, but if delegated to the pure Java implementation would not * call the version of flush() overridden in a Python sub-class of @@ -244,7 +244,7 @@ final void _IOBase_close() { * Is the stream capable of positioning the read/write pointer? * * @return True if may be positioned - * @throws PyException(ValueError) if the object is closed to client operations + * @throws PyException {@code ValueError} if the object is closed to client operations */ public boolean seekable() throws PyException { return _IOBase_seekable(); @@ -260,8 +260,8 @@ final boolean _IOBase_seekable() throws PyException { * positioned. * * @param msg optional custom message - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not capable of being positioned. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not capable of being positioned. */ public void _checkSeekable(String msg) { _IOBase__checkSeekable(msg); @@ -271,8 +271,8 @@ public void _checkSeekable(String msg) { * Raise an error if the pointer of underlying IO stream is not capable of being * positioned. * - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not capable of being positioned. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not capable of being positioned. */ public final void _checkSeekable() { _checkSeekable(null); @@ -289,7 +289,7 @@ final void _IOBase__checkSeekable(String msg) { * Is the stream readable? * * @return true if readable - * @throws PyException(ValueError) if the object is closed to client operations + * @throws PyException {@code ValueError} if the object is closed to client operations */ public boolean readable() throws PyException { return _IOBase_readable(); @@ -304,8 +304,8 @@ final boolean _IOBase_readable() throws PyException { * Raise an error if the underlying IO stream is not readable. * * @param msg optional custom message - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not readable. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not readable. */ public void _checkReadable(String msg) { _IOBase__checkReadable(msg); @@ -314,8 +314,8 @@ public void _checkReadable(String msg) { /** * Raise an error if the underlying IO stream is not readable. * - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not readable. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not readable. */ public final void _checkReadable() { _checkReadable(null); @@ -332,7 +332,7 @@ final void _IOBase__checkReadable(String msg) { * Is the stream writable? * * @return true if writable - * @throws PyException(ValueError) if the object is closed to client operations + * @throws PyException {@code ValueError} if the object is closed to client operations */ public boolean writable() throws PyException { return _IOBase_writable(); @@ -347,8 +347,8 @@ final boolean _IOBase_writable() throws PyException { * Raise an error if the underlying IO stream is not writable. * * @param msg optional custom message - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not writable. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not writable. */ public void _checkWritable(String msg) throws PyException { _IOBase__checkWritable(msg); @@ -357,8 +357,8 @@ public void _checkWritable(String msg) throws PyException { /** * Raise an error if the underlying IO stream is not writable. * - * @throws PyException(ValueError) if the object is closed to client operations - * @throws PyException(IOError) if the stream is not writable. + * @throws PyException {@code ValueError} if the object is closed to client operations + * @throws PyException {@code IOError} if the stream is not writable. */ public final void _checkWritable() throws PyException { _checkWritable(null); @@ -385,7 +385,7 @@ public final boolean closed() { * {@link #_checkSeekable}, etc.. * * @param msg optional custom message - * @throws PyException(ValueError) if the object is closed to client operations + * @throws PyException {@code ValueError} if the object is closed to client operations */ public void _checkClosed(String msg) throws PyException { _IOBase__checkClosed(msg); @@ -471,7 +471,7 @@ final boolean _IOBase_isatty() { * Return one line of text (bytes terminates by '\n'), or the specified number of * bytes, or the whole stream, whichever is shortest. * - * @param limit maximum number of bytes (<0 means no limit) + * @param limit maximum number of bytes (<0 means no limit) * @return the line (or fragment) */ public PyObject readline(int limit) { @@ -543,9 +543,7 @@ private PyObject _readline(int limit) { if (peekResult.__nonzero__()) { // Get a look at the bytes themselves - PyBuffer peekBuffer = readablePyBuffer(peekResult); - - try { + try (PyBuffer peekBuffer = readablePyBuffer(peekResult)) { /* * Scan forwards in the peek buffer to see if there is an end-of-line. Most * frequently this succeeds. The number of bytes to scan is limited to the @@ -569,10 +567,6 @@ private PyObject _readline(int limit) { */ curr = readMethod.__call__(Py.newInteger(p)); remainingLimit -= p; - - } finally { - // We must let go of the buffer we were given - peekBuffer.release(); } } else { @@ -654,9 +648,9 @@ public PyObject __iternext__() { * May be called repeatedly to produce (usually) lines from this stream or file. * * @return next line from the stream or file - * @throws PyException(StopIteration) when iteration has reached a natural conclusion - * @throws PyException(ValueError) if the file or stream is closed - * @throws PyException(IOError) reflecting an I/O error in during the read + * @throws PyException {@code StopIteration} when iteration has reached a natural conclusion + * @throws PyException {@code ValueError} if the file or stream is closed + * @throws PyException {@code IOError} reflecting an I/O error in during the read */ public PyObject next() throws PyException { return _IOBase_next(); @@ -752,13 +746,20 @@ private static PyException tailoredIOError(String msg, String oper) { * * @param obj to be wrapped and presented as a buffer * @return a 1D contiguous PyBuffer of bytes - * @throws PyException (BufferError) if object has buffer API, but is not 1D contiguous bytes - * @throws PyException (TypeError) if object not convertible to a byte array + * @throws PyException {@code BufferError} if object has buffer API, but is not 1D contiguous + * bytes + * @throws PyException {@code TypeError} if object not convertible to a byte array */ protected static PyBuffer readablePyBuffer(PyObject obj) throws PyException { - if (obj instanceof BufferProtocol) { + + // First consider special cases we can view as a String + if (obj instanceof PyUnicode) { + String s = ((PyUnicode) obj).encode(); + return new SimpleStringBuffer(PyBUF.SIMPLE, null, s); + + } else { try { - return ((BufferProtocol)obj).getBuffer(PyBUF.SIMPLE); + return ((BufferProtocol) obj).getBuffer(PyBUF.SIMPLE); } catch (PyException pye) { if (pye.match(Py.BufferError)) { // If we can't get a buffer on the object, say it's the wrong type @@ -766,20 +767,13 @@ protected static PyBuffer readablePyBuffer(PyObject obj) throws PyException { } else { throw pye; } + } catch (ClassCastException pye) { + // fall through to message } - } else { - // Something else we can view as a String? - String s; - if (obj instanceof PyUnicode) { - s = ((PyUnicode)obj).encode(); - } else if (obj instanceof PyArray) { - s = ((PyArray)obj).tostring(); - } else { - // None of the above: complain - throw tailoredTypeError("read-write buffer", obj); - } - return new SimpleStringBuffer(PyBUF.SIMPLE, null, s); } + + // None of the above: complain + throw tailoredTypeError("read-write buffer", obj); } /** @@ -788,25 +782,25 @@ protected static PyBuffer readablePyBuffer(PyObject obj) throws PyException { * * @param obj to be wrapped and presented as a buffer * @return a 1D contiguous PyBuffer of bytes - * @throws PyException (BufferError) if object has buffer API, but is not 1D contiguous bytes - * @throws PyException (TypeError) if object not convertible to a byte array + * @throws PyException {@code BufferError} if object has buffer API, but is not 1D contiguous + * bytes + * @throws PyException {@code TypeError} if object not convertible to a byte array */ protected static PyBuffer writablePyBuffer(PyObject obj) throws PyException { - if (obj instanceof BufferProtocol) { - try { - return ((BufferProtocol)obj).getBuffer(PyBUF.WRITABLE); - } catch (PyException pye) { - if (pye.match(Py.BufferError)) { - // If we can't get a buffer on the object, say it's the wrong type - throw Py.TypeError(String.format("(BufferError) %s", pye.getMessage())); - } else { - throw pye; - } + try { + return ((BufferProtocol) obj).getBuffer(PyBUF.WRITABLE); + } catch (PyException pye) { + if (pye.match(Py.BufferError)) { + // If we can't get a buffer on the object, say it's the wrong type + throw Py.TypeError(String.format("(BufferError) %s", pye.getMessage())); + } else { + throw pye; } - } else { - // Can't be a buffer: complain - throw tailoredTypeError("read-write buffer", obj); + } catch (ClassCastException pye) { + // fall through to message } + // Can't be a buffer: complain + throw tailoredTypeError("read-write buffer", obj); } /** diff --git a/src/org/python/modules/_io/_jyio.java b/src/org/python/modules/_io/_jyio.java index 88a4d65d1..03df2e9a4 100644 --- a/src/org/python/modules/_io/_jyio.java +++ b/src/org/python/modules/_io/_jyio.java @@ -40,9 +40,7 @@ public static void classDictInit(PyObject dict) { PyObject ValueError = exceptions.__getattr__("ValueError"); PyObject IOError = exceptions.__getattr__("IOError"); // Equivalent to class UnsupportedOperation(ValueError, IOError) : pass - // UnsupportedOperation = makeException(dict, "UnsupportedOperation", ValueError, IOError); - // XXX Work-around: slots not properly initialised unless IOError comes first - UnsupportedOperation = makeException(dict, "UnsupportedOperation", IOError, ValueError); + UnsupportedOperation = makeException(dict, "UnsupportedOperation", ValueError, IOError); // Hide from Python dict.__setitem__("classDictInit", null); diff --git a/src/org/python/modules/_json/Encoder.java b/src/org/python/modules/_json/Encoder.java index 38905cf22..d2f1e2d74 100644 --- a/src/org/python/modules/_json/Encoder.java +++ b/src/org/python/modules/_json/Encoder.java @@ -1,11 +1,12 @@ package org.python.modules._json; +import org.python.core.AbstractDict; import org.python.core.ArgParser; import org.python.core.Py; -import org.python.core.PyDictionary; import org.python.core.PyFloat; import org.python.core.PyInteger; import org.python.core.PyLong; +import org.python.core.PyNewWrapper; import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyString; @@ -15,6 +16,7 @@ import org.python.core.Traverseproc; import org.python.core.Visitproc; import org.python.expose.ExposedGet; +import org.python.expose.ExposedNew; import org.python.expose.ExposedType; @ExposedType(name = "_json.encoder", base = PyObject.class) @@ -25,7 +27,7 @@ public class Encoder extends PyObject implements Traverseproc { @ExposedGet public final String __module__ = "_json"; - final PyDictionary markers; + final AbstractDict markers; final PyObject defaultfn; final PyObject encoder; final PyObject indent; @@ -36,13 +38,17 @@ public class Encoder extends PyObject implements Traverseproc { final boolean allow_nan; public Encoder(PyObject[] args, String[] kwds) { - super(); + this(TYPE, args, kwds); + } + + public Encoder(PyType subtype, PyObject[] args, String[] kwds) { + super(subtype); ArgParser ap = new ArgParser("encoder", args, kwds, new String[]{"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan"}); ap.noKeywords(); PyObject m = ap.getPyObject(0); - markers = m == Py.None ? null : (PyDictionary) m; + markers = m == Py.None ? null : (AbstractDict) m; defaultfn = ap.getPyObject(1); encoder = ap.getPyObject(2); indent = ap.getPyObject(3); @@ -53,6 +59,16 @@ public Encoder(PyObject[] args, String[] kwds) { allow_nan = ap.getPyObject(8).__nonzero__(); } + @ExposedNew + static PyObject Encoder___new__(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + if (subtype == TYPE) { + return new Encoder(args, keywords); + } else { + return new EncoderDerived(subtype, args, keywords); + } + } + public PyObject __call__(PyObject obj) { return __call__(obj, Py.Zero); } @@ -115,8 +131,9 @@ private void encode_obj(PyList rval, PyObject obj, int indent_level) { rval.append(encode_float(obj)); } else if (obj instanceof PyList || obj instanceof PyTuple) { encode_list(rval, obj, indent_level); - } else if (obj instanceof PyDictionary) { - encode_dict(rval, (PyDictionary) obj, indent_level); + } else if (obj instanceof AbstractDict) { + /* Using AbstractDict instead of PyDictionary fixes http://bugs.jython.org/issue2622 */ + encode_dict(rval, (AbstractDict) obj, indent_level); } else { PyObject ident = checkCircularReference(obj); if (defaultfn == Py.None) { @@ -131,7 +148,7 @@ private void encode_obj(PyList rval, PyObject obj, int indent_level) { } } - private void encode_dict(PyList rval, PyDictionary dct, int indent_level) { + private void encode_dict(PyList rval, AbstractDict dct, int indent_level) { /* Encode Python dict dct a JSON term */ if (dct.__len__() == 0) { rval.append(new PyString("{}")); diff --git a/src/org/python/modules/_json/EncoderDerived.java b/src/org/python/modules/_json/EncoderDerived.java new file mode 100644 index 000000000..772f57604 --- /dev/null +++ b/src/org/python/modules/_json/EncoderDerived.java @@ -0,0 +1,1175 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.modules._json; + +import java.io.Serializable; +import org.python.core.*; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class EncoderDerived extends Encoder implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + + public String toString() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__repr__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (!(res instanceof PyString)) + throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")"); + return((PyString)res).toString(); + } + return super.toString(); + } + +} diff --git a/src/org/python/modules/_json/Scanner.java b/src/org/python/modules/_json/Scanner.java index 100471f76..32729e139 100644 --- a/src/org/python/modules/_json/Scanner.java +++ b/src/org/python/modules/_json/Scanner.java @@ -1,8 +1,10 @@ package org.python.modules._json; +import org.python.core.ArgParser; import org.python.core.Py; import org.python.core.PyDictionary; import org.python.core.PyList; +import org.python.core.PyNewWrapper; import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyTuple; @@ -11,10 +13,14 @@ import org.python.core.Traverseproc; import org.python.core.Visitproc; import org.python.expose.ExposedGet; +import org.python.expose.ExposedNew; import org.python.expose.ExposedType; +import org.python.modules._io.OpenMode; +import org.python.modules._io.PyFileIO; +import org.python.modules._io.PyFileIODerived; -@ExposedType(name = "_json.Scanner", base = PyObject.class) +@ExposedType(name = "_json.scanner", base = PyObject.class) public class Scanner extends PyObject implements Traverseproc { public static final PyType TYPE = PyType.fromClass(Scanner.class); @@ -31,7 +37,11 @@ public class Scanner extends PyObject implements Traverseproc { final PyObject parse_constant; public Scanner(PyObject context) { - super(); + this(TYPE, context); + } + + public Scanner(PyType subtype, PyObject context) { + super(subtype); encoding = _castString(context.__getattr__("encoding"), "utf-8"); strict = context.__getattr__("strict").__nonzero__(); object_hook = context.__getattr__("object_hook"); @@ -45,6 +55,22 @@ public PyObject __call__(PyObject string, PyObject idx) { return _scan_once((PyString)string, idx.asInt()); } + private static final String[] newArgs = {"context"}; + + @ExposedNew + static PyObject Scanner___new__(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + + ArgParser ap = new ArgParser("scanner", args, keywords, newArgs, 1); + PyObject context = ap.getPyObject(0); + + if (subtype == TYPE) { + return new Scanner(context); + } else { + return new ScannerDerived(subtype, context); + } + } + private static boolean IS_WHITESPACE(int c) { return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'); } diff --git a/src/org/python/modules/_json/ScannerDerived.java b/src/org/python/modules/_json/ScannerDerived.java new file mode 100644 index 000000000..d1663274e --- /dev/null +++ b/src/org/python/modules/_json/ScannerDerived.java @@ -0,0 +1,1175 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.modules._json; + +import java.io.Serializable; +import org.python.core.*; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class ScannerDerived extends Scanner implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + + public String toString() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__repr__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (!(res instanceof PyString)) + throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")"); + return((PyString)res).toString(); + } + return super.toString(); + } + +} diff --git a/src/org/python/modules/_locale/CEmulationLocale.java b/src/org/python/modules/_locale/CEmulationLocale.java new file mode 100644 index 000000000..f4d83bc89 --- /dev/null +++ b/src/org/python/modules/_locale/CEmulationLocale.java @@ -0,0 +1,129 @@ +// (c) 2019 Jython Developers +// Licensed to PSF under a contributor agreement + +package org.python.modules._locale; + +import org.python.core.Py; +import org.python.core.PyDictionary; +import org.python.core.PyList; +import org.python.core.PyString; + +/** + * Emulates the Python (ie POSIX) 'C' locale. + * + * The C emulation locale uses only ANSI characters in non-unicode strings, in keeping with it being + * the locale of last resort and maximum compatibility. + * + * Used by the _locale module. Callers would not usually interact with this class directly unless + * working with _locale internals. + * + * @since Jython 2.7.2 + */ +public class CEmulationLocale implements PyLocale { + /* + * A number of these structures are repeated from Time.java and elsewhere They can be removed + * from those other classes and pointed here once jython2_legacy behaviour is deprecated or + * removed. + */ + private static final String[] EN_SHORT_DAYS = + new String[] {"", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + + private static final String[] EN_DAYS = new String[] {"", "Sunday", "Monday", "Tuesday", + "Wednesday", "Thursday", "Friday", "Saturday"}; + + private static final String[] EN_SHORT_MONTHS = new String[] {"Jan", "Feb", "Mar", "Apr", "May", + "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + private static final String[] EN_MONTHS = new String[] {"January", "February", "March", "April", + "May", "June", "July", "August", "September", "October", "November", "December"}; + + private static final String[] EN_AM_PM = new String[] {"am", "pm"}; + + private static final PyDictionary EMULATION_CONV; + + private static void putEmpty(PyDictionary dict, String key) { + dict.put(new PyString(key), Py.EmptyString); + } + + private static void putCharMax(PyDictionary dict, String key) { + dict.put(new PyString(key), _locale.CHAR_MAX_PY_INT); + } + + static { + EMULATION_CONV = new PyDictionary(); + /* + * This is a repetition of the locale emulation in the locale module to allow resetting the + * locale back to C emulation. + */ + _locale.putConvEntry(EMULATION_CONV, "decimal_point", "."); + putEmpty(EMULATION_CONV, "thousands_sep"); + putEmpty(EMULATION_CONV, "currency_symbol"); + putEmpty(EMULATION_CONV, "int_curr_symbol"); + putEmpty(EMULATION_CONV, "negative_sign"); + putEmpty(EMULATION_CONV, "positive_sign"); + putCharMax(EMULATION_CONV, "p_sign_posn"); + PyList groupingList = new PyList(); + _locale.putConvEntry(EMULATION_CONV, "grouping", groupingList); + putEmpty(EMULATION_CONV, "mon_decimal_point"); + putEmpty(EMULATION_CONV, "mon_thousands_sep"); + putCharMax(EMULATION_CONV, "frac_digits"); + putCharMax(EMULATION_CONV, "int_frac_digits"); + _locale.putConvEntry(EMULATION_CONV, "mon_grouping", groupingList); + putCharMax(EMULATION_CONV, "n_sign_posn"); + putCharMax(EMULATION_CONV, "p_cs_precedes"); + putCharMax(EMULATION_CONV, "n_cs_precedes"); + putCharMax(EMULATION_CONV, "p_sep_by_space"); + putCharMax(EMULATION_CONV, "n_sep_by_space"); + } + + @Override + public PyDictionary localeconv() { + return EMULATION_CONV; + } + + @Override + public PyString getLocaleString() { + return _locale.C_LOCALE_PY_STRING; + } + + @Override + public PyString getUnderlyingLocale() { + return _locale.C_LOCALE_PY_STRING; + } + + @Override + public int strcoll(PyString str1, PyString str2) { + return str1.__cmp__(str2); + } + + @Override + public PyString strxfrm(PyString str1) { + return str1; + } + + @Override + public String[] getShortWeekdays() { + return EN_SHORT_DAYS; + } + + @Override + public String[] getWeekdays() { + return EN_DAYS; + } + + @Override + public String[] getShortMonths() { + return EN_SHORT_MONTHS; + } + + @Override + public String[] getMonths() { + return EN_MONTHS; + } + + @Override + public String[] getAmPmStrings() { + return EN_AM_PM; + } + +} \ No newline at end of file diff --git a/src/org/python/modules/_locale/DateSymbolJyLocale.java b/src/org/python/modules/_locale/DateSymbolJyLocale.java new file mode 100644 index 000000000..b369e8c78 --- /dev/null +++ b/src/org/python/modules/_locale/DateSymbolJyLocale.java @@ -0,0 +1,51 @@ +package org.python.modules._locale; + +import java.text.DateFormatSymbols; +import java.util.Locale; + +/** + * Separating these largely constant values from Python encoding conversions allows for safer + * initialization even if modules are loaded in different orders. The Python {@code locale} and + * {@code codecs} modules have interdependencies, as well as {@link org.python.modules.time.Time} + * and {@link org.python.modules._locale._locale}. The latter in particular depends on + * {@code java.util.Locale} and this class, but only uses the date symbol aspect. + * + * @since Jython 2.7.2 + */ +public class DateSymbolJyLocale implements DateSymbolLocale { + + protected final Locale locale; + protected final DateFormatSymbols dfSymbols; + + public DateSymbolJyLocale(Locale locale) { + super(); + this.locale = locale; + this.dfSymbols = DateFormatSymbols.getInstance(locale); + } + + @Override + public String[] getShortWeekdays() { + return dfSymbols.getShortWeekdays(); + } + + @Override + public String[] getWeekdays() { + return dfSymbols.getWeekdays(); + } + + @Override + public String[] getShortMonths() { + return dfSymbols.getShortMonths(); + } + + @Override + public String[] getMonths() { + return dfSymbols.getMonths(); + } + + @Override + public String[] getAmPmStrings() { + return dfSymbols.getAmPmStrings(); + } + +} \ No newline at end of file diff --git a/src/org/python/modules/_locale/DateSymbolLocale.java b/src/org/python/modules/_locale/DateSymbolLocale.java new file mode 100644 index 000000000..8a3a7c386 --- /dev/null +++ b/src/org/python/modules/_locale/DateSymbolLocale.java @@ -0,0 +1,20 @@ +package org.python.modules._locale; + +/** + * Date related string values. + * + * @since Jython 2.7.2 + */ +public interface DateSymbolLocale { + + public String[] getShortWeekdays(); + + public String[] getShortMonths(); + + public String[] getMonths(); + + public String[] getAmPmStrings(); + + public String[] getWeekdays(); + +} \ No newline at end of file diff --git a/src/org/python/modules/_locale/JyLocale.java b/src/org/python/modules/_locale/JyLocale.java new file mode 100644 index 000000000..95fffd9ad --- /dev/null +++ b/src/org/python/modules/_locale/JyLocale.java @@ -0,0 +1,221 @@ +// (c) 2019 Jython Developers +// Licensed to PSF under a contributor agreement + +package org.python.modules._locale; + +import java.text.Collator; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; + +import org.python.core.Py; +import org.python.core.PyDictionary; +import org.python.core.PyException; +import org.python.core.PyInteger; +import org.python.core.PyList; +import org.python.core.PyString; +import org.python.core.PyUnicode; + +/** + * Sources locale information from standard Java API functions, such as that in + * {@link java.util.Locale} and {@link java.text.DecimalFormat}. + * + * Used by the _locale module. Callers would not usually interact with this class directly unless + * working with _locale internals. + * + * @since Jython 2.7.2 + */ +public class JyLocale extends DateSymbolJyLocale implements PyLocale { + + private final String encoding; + private final PyDictionary conv; + private final Collator collator; + + public JyLocale(Locale locale, String encoding) { + super(locale); + this.encoding = encoding; + this.conv = initLocaleConv(); + this.collator = Collator.getInstance(locale); + } + + @Override + public PyDictionary localeconv() { + return conv; + } + + private PyDictionary initLocaleConv() { + DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(locale); + DecimalFormat cf = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + return localeConvForFormat(df, cf, getEncoding()); + } + + /** + * Fallbacks provided for charset conversion failures in this method match either the C locale, + * or plausible lower-risk substitutes, like ISO currency code for currency symbol. + */ + static PyDictionary localeConvForFormat(DecimalFormat decimalFormat, + DecimalFormat currencyFormat, String encoding) { + PyDictionary result = new PyDictionary(); + DecimalFormatSymbols dfs = decimalFormat.getDecimalFormatSymbols(); + DecimalFormatSymbols cfs = currencyFormat.getDecimalFormatSymbols(); + putConvUnicodeEntry(result, "decimal_point", dfs.getDecimalSeparator(), ".", encoding); + putConvUnicodeEntry(result, "thousands_sep", dfs.getGroupingSeparator(), "", encoding); + putConvUnicodeEntry(result, "currency_symbol", cfs.getCurrencySymbol(), + dfs.getInternationalCurrencySymbol(), encoding); + _locale.putConvEntry(result, "int_curr_symbol", cfs.getInternationalCurrencySymbol()); + putConvUnicodeEntry(result, "negative_sign", cfs.getMinusSign(), "-", encoding); + // No positive sign concept in Java locale + _locale.putConvEntry(result, "positive_sign", new PyString("")); + _locale.putConvEntry(result, "p_sign_posn", new PyInteger(3)); + PyList groupingList = new PyList(); + groupingList.add(new PyInteger(decimalFormat.getGroupingSize())); + groupingList.add(new PyInteger(0)); + _locale.putConvEntry(result, "grouping", groupingList); + _locale.putConvEntry(result, "mon_decimal_point", cfs.getMonetaryDecimalSeparator()); + putConvUnicodeEntry(result, "mon_thousands_sep", cfs.getGroupingSeparator(), "", encoding); + _locale.putConvEntry(result, "frac_digits", + new PyInteger(currencyFormat.getMaximumFractionDigits())); + _locale.putConvEntry(result, "int_frac_digits", + new PyInteger(currencyFormat.getMaximumFractionDigits())); + PyList monGroupingList = new PyList(); + monGroupingList.add(new PyInteger(currencyFormat.getGroupingSize())); + monGroupingList.add(new PyInteger(0)); + _locale.putConvEntry(result, "mon_grouping", monGroupingList); + _locale.putConvEntry(result, "n_sign_posn", + new PyInteger(negativeSignPosition(currencyFormat))); + _locale.putConvEntry(result, "p_cs_precedes", + new PyInteger(positiveCurrencyPrecedesValue(currencyFormat))); + _locale.putConvEntry(result, "n_cs_precedes", + new PyInteger(negativeCurrencyPrecedesValue(currencyFormat))); + _locale.putConvEntry(result, "p_sep_by_space", + new PyInteger(positiveSeparatedBySpace(currencyFormat))); + _locale.putConvEntry(result, "n_sep_by_space", + new PyInteger(negativeSeparatedBySpace(currencyFormat))); + return result; + } + + private static void putConvUnicodeEntry(PyDictionary result, String key, String value, + String fallback, String encoding) { + try { + result.put(new PyString(key), new PyString(new PyUnicode(value).encode(encoding))); + } catch (PyException pye) { + encodingFallback(result, key, fallback, pye); + } + } + + private static void putConvUnicodeEntry(PyDictionary result, String key, char value, + String fallback, String encoding) { + try { + result.put(new PyString(key), new PyString(new PyUnicode(value).encode(encoding))); + } catch (PyException pye) { + encodingFallback(result, key, fallback, pye); + } + } + + private static void encodingFallback(PyDictionary result, String key, String fallback, + PyException pye) { + Py.writeComment("_locale", + "Could not encode value for key " + key + " " + pye.getMessage()); + result.put(new PyString(key), new PyString(fallback)); + } + + @Override + public PyString getLocaleString() { + return new PyString(locale.toString() + "." + encoding); + } + + @Override + public PyString getUnderlyingLocale() { + return new PyString(locale.toString()); + } + + @Override + public int strcoll(PyString str1, PyString str2) { + return collator.compare(unicoder(str1), unicoder(str2)); + } + + private String unicoder(PyString str) { + return strxfrm(str).toString(); + } + + @Override + public PyString strxfrm(PyString str) { + if (str instanceof PyUnicode) { + return str; + } + return (PyString) str.decode(encoding); + } + + public String getEncoding() { + return encoding; + } + + static int negativeSignPosition(DecimalFormat df) { + String prefix = df.getNegativePrefix(); + String suffix = df.getNegativeSuffix(); + if ("".equals(suffix)) { + if ("".equals(prefix)) { + // Nothing is specified in this locale. + return _locale.CHAR_MAX; + } + } + if (prefix.startsWith("(") && suffix.endsWith(")")) { + // Currency and value are surrounded by parentheses. + return 0; + } + final String MINUS = String.valueOf(df.getDecimalFormatSymbols().getMinusSign()); + if (prefix.startsWith(MINUS)) { + // The sign should precede the value and currency symbol. + return 1; + } else if (prefix.endsWith(MINUS)) { + // The sign should immediately precede the value. + return 3; + } else if (suffix.startsWith(MINUS)) { + // The sign should immediately follow the value. + return 4; + } + // The sign should follow the value and currency symbol. + return 2; + } + + static int positiveCurrencyPrecedesValue(DecimalFormat df) { + return currencyPrecedesValue(df, df.getPositivePrefix()); + } + + static int negativeCurrencyPrecedesValue(DecimalFormat df) { + return currencyPrecedesValue(df, df.getNegativePrefix()); + } + + private static int currencyPrecedesValue(DecimalFormat df, String prefix) { + if (prefix.contains(df.getDecimalFormatSymbols().getCurrencySymbol())) { + return 1; + } + return 0; + } + + static int positiveSeparatedBySpace(DecimalFormat df) { + return separatedBySpace(df.getPositivePrefix(), df.getPositiveSuffix()); + } + + static int negativeSeparatedBySpace(DecimalFormat df) { + return separatedBySpace(df.getNegativePrefix(), df.getNegativeSuffix()); + } + + private static int separatedBySpace(String prefix, String suffix) { + if ((!prefix.isEmpty() && isExtendedWhitespace(prefix.charAt(prefix.length() - 1)))) { + return 1; + } else if ((!suffix.isEmpty() && isExtendedWhitespace(suffix.charAt(0)))) { + return 1; + } + return 0; + } + + /** + * Includes non-breaking space, but not extended codepoints + */ + public static boolean isExtendedWhitespace(char c) { + return Character.isWhitespace(c) || '\u00A0' == c; + } + +} \ No newline at end of file diff --git a/src/org/python/modules/_locale/PyLocale.java b/src/org/python/modules/_locale/PyLocale.java new file mode 100644 index 000000000..426f99070 --- /dev/null +++ b/src/org/python/modules/_locale/PyLocale.java @@ -0,0 +1,28 @@ +// (c) 2019 Jython Developers +// Licensed to PSF under a contributor agreement + +package org.python.modules._locale; + +import org.python.core.PyDictionary; +import org.python.core.PyString; + +/** + * Definition of a Python native locale implementation. Based on Python locale module behaviour and + * implicit dependencies, and the {@code _localemodule.c} implementation in CPython. + * + * It is recommended classes implementing this interface are made immutable. + * + * @since Jython 2.7.2 + */ +public interface PyLocale extends DateSymbolLocale { + + public PyDictionary localeconv(); + + public PyString getLocaleString(); + + public PyString getUnderlyingLocale(); + + public int strcoll(PyString str1, PyString str2); + + public PyString strxfrm(PyString str1); +} diff --git a/src/org/python/modules/_locale/_locale.java b/src/org/python/modules/_locale/_locale.java new file mode 100644 index 000000000..b3449c588 --- /dev/null +++ b/src/org/python/modules/_locale/_locale.java @@ -0,0 +1,376 @@ +// (c) 2019 Jython Developers +// Licensed to PSF under a contributor agreement + +package org.python.modules._locale; + +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + +import org.python.core.ClassDictInit; +import org.python.core.Py; +import org.python.core.PyDictionary; +import org.python.core.PyException; +import org.python.core.PyInteger; +import org.python.core.PyObject; +import org.python.core.PyString; +import org.python.core.PyStringMap; +import org.python.core.PySystemState; + +import static org.python.core.RegistryKey.PYTHON_LOCALE_CONTROL; + +/** + * Java native implementation of underlying locale functions, fitting the interface defined or + * implied by the Python locale module. + * + * Functional documentation can be found in the Python module docstring. This class depends on + * registry key {@link org.python.core.RegistryKey#PYTHON_LOCALE_CONTROL}. Additional implementation + * details for users of this class are captured below. + *

    + * Unicode. In general, Java and its locale settings are quite unicode heavy, making rich use of + * different symbols for e.g. currencies. This solution allows some of that to leak through by + * encoding the Java locale value with the current character encoding. The Python locale module is + * quite conservative and tends to keep things as solely strings. Python 2.x usually supports only + * string / ascii by default in many cases, and only unicode when asked. This is a little less + * conservative while only allowing values consistent with the current encoding. + *

    + * An example of this is some Python implementations using EUR rather than the Euro symbol € + * ({@code 'u20ac'}), probably because € is only available in Unicode. In the Java implementation, + * if UTF-8 encoding is set, the resulting entry in {@code localeconv()['currency_code']} is + * {@code '\xe2\x82\xac'}. This can be used by {@code print()} and related functions directly. + * Encoding failures for {@code currency_symbol} fall back to {@code int_curr_symbol} (eg EUR). + * Encoding failures for {@code negative_sign}, which are sometimes unicode, fall back to an ANSI + * hyphen ('-'). Other encoding failures fallback to the 'C' locale values, where possible. + *

    + * The C emulation locale uses only ANSI characters in non-unicode strings, in keeping with it being + * the locale of last resort and maximum compatibility. + *

    + * Positive sign position ({@code p_sign_posn}) is not a distinguished concept in Java and so this + * is hardcoded to 3. + *

    + * This class ensures read/write consistency, when changing locales via + * {@link #setlocale(PyInteger,PyString)}, by declaring private variable {@code currentLocale} as + * volatile, and only assigning it immutable objects. It does not lock to guarantee sequencing of + * {@code setLocale()} calls from separate threads. In the rare cases where that would be needed, it + * is the responsibility of the calling code. + * + * @since Jython 2.7.2 + */ +public class _locale implements ClassDictInit { + + /** + * The {@code locale} module exposes {@code _locale.Error} as {@code locale.Error}. Some Python + * functions, including {@code strptime()}, depend on {@code locale.Error}, making it part of + * the public API for native locale implementations. + */ + public static PyObject Error; + + public static PyException LocaleException(String message) { + return new PyException(Error, message); + } + + // @formatter:off + public static final PyString __doc__ = new PyString( + "The _locale module exposes locale functions in the underlying " + + "operating system or platform in a consistent way, for use by " + + "the Python locale module. It is a native Java implementation, " + + "paralleling libmodule.c in CPython and its dependence on C " + + "libraries provided by the OS.\n" + + "This module is currently in beta, and is enabled with the " + + "registry property ``python.locale.control``. It is " + + "disabled by default, resulting in jython 2.7.1 (and previous) " + + "locale behaviour.\n" + + "\n" + + "+-------------------+-----------------------------------------+\n" + + "+ Property Value + Behaviour |\n" + + "+===================+=========================================+\n" + + "| jython2_legacy | Mix of implicit Java locale and |\n" + + "| | emulated 'C'. Text and date formatting |\n" + + "| | mostly Java locale (eg ``%b``). |\n" + + "| | ``asctime()`` matches C emulation |\n" + + "| | ``setlocale()`` always errors by design.|\n" + + "| | This matches version 2.7.1 and previous |\n" + + "| | behaviour. Will be deprecated in future |\n" + + "| | versions. |\n" + + "+-------------------+-----------------------------------------+\n" + + "| settable | Java platform locale services made |\n" + + "| | available via locale module. |\n" + + "| | ``setlocale()`` works, using Java locale|\n" + + "| | identifiers and LC_ALL (only). C locale |\n" + + "| | available via ``setlocale()``. Initial |\n" + + "| | locale and encoding per Java defaults. |\n" + + "+-------------------+-----------------------------------------+\n" + + "| '' or unset | As per ``jython2_legacy``. |\n" + + "| | In future versions, per ``settable``. |\n" + + "+-------------------+-----------------------------------------+\n"); + // @formatter:on + + public static final String LOCALE_CONTROL_SETTABLE = "settable"; + public static final String LOCALE_CONTROL_JYTHON2_LEGACY = "jython2_legacy"; + + // These values are the same as glibc locale/bits/locale.h + // Specific integer constants are not mandated by the POSIX locale spec, so an existing + // standard seemed as good an arbitrary set of values as any + private static final int __LC_CTYPE = 0; + private static final int __LC_NUMERIC = 1; + private static final int __LC_TIME = 2; + private static final int __LC_COLLATE = 3; + private static final int __LC_MONETARY = 4; + private static final int __LC_MESSAGES = 5; + private static final int __LC_ALL = 6; + @SuppressWarnings("unused") + private static final int __LC_PAPER = 7; + @SuppressWarnings("unused") + private static final int __LC_NAME = 8; + @SuppressWarnings("unused") + private static final int __LC_ADDRESS = 9; + @SuppressWarnings("unused") + private static final int __LC_TELEPHONE = 10; + @SuppressWarnings("unused") + private static final int __LC_MEASUREMENT = 11; + @SuppressWarnings("unused") + private static final int __LC_IDENTIFICATION = 12; + + public static final PyInteger LC_CTYPE = new PyInteger(__LC_CTYPE); + public static final PyInteger LC_NUMERIC = new PyInteger(__LC_NUMERIC); + public static final PyInteger LC_TIME = new PyInteger(__LC_TIME); + public static final PyInteger LC_COLLATE = new PyInteger(__LC_COLLATE); + public static final PyInteger LC_MONETARY = new PyInteger(__LC_MONETARY); + public static final PyInteger LC_MESSAGES = new PyInteger(__LC_MESSAGES); + public static final PyInteger LC_ALL = new PyInteger(__LC_ALL); + // Remaining constants not used by locale.py so are not exposed here + + // 127 chosen as consistent with hardcoded default in locale.py for C locale + public static final int CHAR_MAX = 127; + public static final PyInteger CHAR_MAX_PY_INT = new PyInteger(127); + public static final PyString C_LOCALE_PY_STRING = new PyString("C"); + private static final Set AVAILABLE_LOCALES; + + // Failsafe for date symbols only. Insufficient for full locale module behaviour. + private static final DateSymbolLocale DEFAULT_LOCALE = + new DateSymbolJyLocale(Locale.getDefault()); + + // This has a subtle initialization dependency on the codecs module due to the initialization + // in JyLocale(). Let the interpreter initialize via classDictInit(). + private static volatile PyLocale currentLocale = null; + + static { + final Set set = new HashSet<>(Arrays.asList(Locale.getAvailableLocales())); + AVAILABLE_LOCALES = Collections.unmodifiableSet(set); + } + + @SuppressWarnings("serial") + public static void initClassExceptions(PyObject exceptions) { + PyObject baseException = exceptions.__finditem__("BaseException"); + Error = Py.makeClass("locale.Error", baseException, new PyStringMap() { + + { + __setitem__("__module__", Py.newString("locale")); + } + }); + } + + // This is used when the module is first initialized, or when simulating re-initialization from + // tests + public static void classDictInit(PyObject dict) { + dict.__setitem__("Error", Error); + try { + changeCurrentLocaleToDefault(); + } catch (Throwable t) { + throw Py.ImportError( + "Jython failed to load default Java locale, falling back. " + t.getMessage()); + } + final String localeControl = PySystemState.registry.getProperty(PYTHON_LOCALE_CONTROL, ""); + if ("".equals(localeControl) || LOCALE_CONTROL_JYTHON2_LEGACY.equals(localeControl)) { + throw Py.ImportError( + "Jython locale support not enabled with python.locale.control, falling back"); + } + if (!LOCALE_CONTROL_SETTABLE.equals(localeControl)) { + throw Py.ImportError( + "Jython locale support python.locale.control unrecognized value, falling back"); + } + changeCurrentLocaleToC(); + } + + private static void changeCurrentLocaleToDefault() { + currentLocale = new JyLocale(Locale.getDefault(), Charset.defaultCharset().name()); + } + + /** + * Put {@code key} mapping to {@code value} into {@code result}, converting to {@code PyString}s + * as needed + */ + protected static void putConvEntry(PyDictionary result, String key, String value) { + try { + result.put(new PyString(key), new PyString(value)); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException(iae.getMessage() + " for key " + key); + } + } + + /** + * Put {@code key} mapping to {@code value} into {@code result}, converting to {@code PyString}s + * as needed + */ + protected static void putConvEntry(PyDictionary result, String key, char value) { + try { + result.put(new PyString(key), new PyString(value)); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException(iae.getMessage() + " for key " + key); + } + } + + /** + * Put {@code key} mapping to {@code value} into {@code result}, converting {@code key} to + * {@code PyString}. + */ + protected static void putConvEntry(PyDictionary result, String key, PyObject value) { + try { + result.put(new PyString(key), value); + } catch (IllegalArgumentException iae) { + throw new IllegalArgumentException(iae.getMessage() + " for key " + key); + } + } + + public static PyString __doc___localeconv = + new PyString("Database of local conventions, mapped from Java.\n" + + "Note that Java locale information is relatively unicode-rich, " + + "particularly for currency symbols. Where that is not supported " + + "by the current encoding, the international currency symbol is "// + + "used.\n"// + + "C locale emulation matches CPython C locale emulation."); + + public static PyDictionary localeconv() { + return currentLocale.localeconv(); + } + + public static PyString __doc___strcoll = + new PyString("Compare Java (unicode) strings using the Java collator for the " + + "current locale, and the encoding normalization provided by strxfrm\n." + + "In the 'C' locale, this simply calls str.__cmp__() "); + + public static int strcoll(PyString str1, PyString str2) { + return currentLocale.strcoll(str1, str2); + } + + public static PyString __doc___strxfrm = + new PyString("Normalize a string to unicode, for common comparison, using the " + + "locale encoding.\n" + + "In the 'C' locale, this is a no-op, returning the parameter."); + + public static PyString strxfrm(PyString str1) { + return currentLocale.strxfrm(str1); + } + + public static PyString __doc___setlocale = + new PyString("Sets the locale given a category and normalized locale string.\n" + + "Only category LC_ALL is supported. Other categories such as " + + "LC_TIME or LC_NUMERIC result in a locale.Error." + "\n"// + + "Normalized format is per RFC 1766, but using underscores instead " + + "of dashes, eg zh_CH.UTF-8. Briefly, the format is " + + "[language]_[locality].[encoding], where [language] is a two " + + "character language identifer, locality is a regional indicator, " + + "and encoding is a character encoding. Other examples are " + + "en_AU.ISO8859-1 and de_DE.ISO8859-15.\n" + + "If this is an empty locale, the same language tag will be tried " + + "with dashes instead of underscores, ie [lanuage]-[locality].\n" + + "Normalization would usually be done by the enclosing locale module.\n" + + "This function treats a missing encoding as using UTF-8.\n"); + + public static PyString setlocale(PyInteger category) { + return currentLocale.getLocaleString(); + } + + /** + * Java Locale loading behaviour is quite forgiving, or uninformative, depending on your + * perspective. It will return a dummy locale for any language tag that fits the syntax, or make + * various attempts to approximate a locale. This solution instead follows the stricter Python + * behaviour of requiring a particular locale to be installed. + */ + public static PyString setlocale(PyInteger category, PyString locale) { + Py.writeDebug("_locale", "setlocale(category,locale==" + locale + ")"); + if (locale == null || locale.equals(Py.None) + || locale.equals(currentLocale.getLocaleString())) { + return setlocale(category); + } + if (!category.equals(LC_ALL)) { + // Py.NotImplementedError not used as dependencies exist on + // locale.Error + throw LocaleException("Only LC_ALL is supported in this version of Jython"); + } + if (locale.equals(C_LOCALE_PY_STRING)) { + changeCurrentLocaleToC(); + return C_LOCALE_PY_STRING; + } + if (locale.equals(new PyString(""))) { + changeCurrentLocaleToDefault(); + } else { + changeLocaleFromLocaleString(locale); + } + return currentLocale.getLocaleString(); + } + + private static void changeLocaleFromLocaleString(PyString locale) { + String localeStr = locale.toString(); + String[] localeParts = localeStr.split("\\."); + String language; + String encoding = "UTF-8"; + if (localeParts.length >= 3) { + throw LocaleException("Does not conform to [language]_[locality].[encoding] format: " + + locale.toString()); + } + if (localeParts.length == 1) { + language = localeStr; + } else { + // == 2 + language = localeParts[0]; + encoding = localeParts[1]; + } + Locale newLocale = loadLocale(language); + if (!isAvailableLocale(newLocale)) { + String underscoreAlias = language.replace('_', '-'); + // Not only are these often switched in Java, Locale.toLanguageTag() uses "-" and + // Locale.toString() uses "_" + newLocale = loadLocale(underscoreAlias); + if (!isAvailableLocale(newLocale)) { + throw LocaleException("unsupported locale setting: " + locale.toString()); + } + } + changeCurrentLocale(new JyLocale(newLocale, encoding)); + } + + private static void changeCurrentLocaleToC() { + changeCurrentLocale(new CEmulationLocale()); + } + + private static boolean isAvailableLocale(Locale locale) { + return locale != null && !locale.toString().isEmpty() && AVAILABLE_LOCALES.contains(locale); + } + + private static Locale loadLocale(String language) { + Locale newLocale = Locale.forLanguageTag(language); + Py.writeDebug("_locale", "Current: " + currentLocale.getUnderlyingLocale()); + Py.writeDebug("_locale", "New: " + newLocale + " loaded with tag: " + language); + return newLocale; + } + + private static void changeCurrentLocale(PyLocale pyLocale) { + Py.writeDebug("_locale", "Locale changed to: " + pyLocale.getLocaleString()); + currentLocale = pyLocale; + } + + /** + * Current {@code DateSymbolLocale} used by the Python interpreter. This object will no longer + * reflect the current state after subsequent calls to {@code setlocale}. + */ + public static DateSymbolLocale getDateSymbolLocale() { + if (currentLocale == null) { + return DEFAULT_LOCALE; + } + return currentLocale; + } + +} diff --git a/src/org/python/modules/_marshal.java b/src/org/python/modules/_marshal.java index 860bfd452..b86f72234 100644 --- a/src/org/python/modules/_marshal.java +++ b/src/org/python/modules/_marshal.java @@ -1,25 +1,31 @@ package org.python.modules; -import java.math.BigInteger; import org.python.core.BaseSet; +import org.python.core.BufferProtocol; import org.python.core.ClassDictInit; -import org.python.core.PyObject; -import org.python.core.PyString; import org.python.core.Py; +import org.python.core.PyBUF; +import org.python.core.PyBuffer; import org.python.core.PyBytecode; import org.python.core.PyComplex; import org.python.core.PyDictionary; +import org.python.core.PyException; import org.python.core.PyFloat; import org.python.core.PyFrozenSet; import org.python.core.PyInteger; import org.python.core.PyList; import org.python.core.PyLong; +import org.python.core.PyObject; import org.python.core.PySet; +import org.python.core.PyString; import org.python.core.PyTuple; +import org.python.core.PyType; import org.python.core.PyUnicode; import org.python.core.Traverseproc; import org.python.core.Visitproc; +import java.math.BigInteger; + public class _marshal implements ClassDictInit { public static void classDictInit(PyObject dict) { @@ -46,7 +52,6 @@ public static void classDictInit(PyObject dict) { private final static char TYPE_DICT = '{'; private final static char TYPE_CODE = 'c'; private final static char TYPE_UNICODE = 'u'; - private final static char TYPE_UNKNOWN = '?'; private final static char TYPE_SET = '<'; private final static char TYPE_FROZENSET = '>'; private final static int MAX_MARSHAL_STACK_DEPTH = 2000; @@ -113,13 +118,12 @@ private void write_long64(long x) { // writes output in 15 bit "digits" private void write_long(BigInteger x) { - int sign = x.signum(); - if (sign < 0) { + boolean negative = x.signum() < 0; + if (negative) { x = x.negate(); } - int num_bits = x.bitLength(); - int num_digits = num_bits / 15 + (num_bits % 15 == 0 ? 0 : 1); - write_int(sign < 0 ? -num_digits : num_digits); + int num_digits = (x.bitLength() + 14) / 15; + write_int(negative ? -num_digits : num_digits); BigInteger mask = BigInteger.valueOf(0x7FFF); for (int i = 0; i < num_digits; i++) { write_short(x.and(mask).shortValue()); @@ -150,98 +154,109 @@ private void write_object(PyObject v, int depth) { write_byte(TYPE_FALSE); } else if (v == Py.True) { write_byte(TYPE_TRUE); - } else if (v instanceof PyInteger) { - write_byte(TYPE_INT); - write_int(((PyInteger) v).asInt()); - } else if (v instanceof PyLong) { - write_byte(TYPE_LONG); - write_long(((PyLong) v).getValue()); - } else if (v instanceof PyFloat) { - if (version == CURRENT_VERSION) { - write_byte(TYPE_BINARY_FLOAT); - write_binary_float((PyFloat) v); - } else { - write_byte(TYPE_FLOAT); - write_float((PyFloat) v); - } - } else if (v instanceof PyComplex) { - PyComplex x = (PyComplex) v; - if (version == CURRENT_VERSION) { - write_byte(TYPE_BINARY_COMPLEX); - write_binary_float(x.getReal()); - write_binary_float(x.getImag()); - } else { - write_byte(TYPE_COMPLEX); - write_float(x.getReal()); - write_float(x.getImag()); - } - } else if (v instanceof PyUnicode) { - write_byte(TYPE_UNICODE); - String buffer = ((PyUnicode) v).encode("utf-8").toString(); - write_int(buffer.length()); - write_string(buffer); - } else if (v instanceof PyString) { - // ignore interning - write_byte(TYPE_STRING); - write_int(v.__len__()); - write_string(v.toString()); - } else if (v instanceof PyTuple) { - write_byte(TYPE_TUPLE); - PyTuple t = (PyTuple) v; - int n = t.__len__(); - write_int(n); - for (int i = 0; i < n; i++) { - write_object(t.__getitem__(i), depth + 1); - } - } else if (v instanceof PyList) { - write_byte(TYPE_LIST); - PyList list = (PyList) v; - int n = list.__len__(); - write_int(n); - for (int i = 0; i < n; i++) { - write_object(list.__getitem__(i), depth + 1); - } - } else if (v instanceof PyDictionary) { - write_byte(TYPE_DICT); - PyDictionary dict = (PyDictionary) v; - for (PyObject item : dict.iteritems().asIterable()) { - PyTuple pair = (PyTuple) item; - write_object(pair.__getitem__(0), depth + 1); - write_object(pair.__getitem__(1), depth + 1); - } - write_object(null, depth + 1); - } else if (v instanceof BaseSet) { - if (v instanceof PySet) { - write_byte(TYPE_SET); + } else { + PyType vt = v.getType(); + if (vt == PyInteger.TYPE) { + write_byte(TYPE_INT); + write_int(((PyInteger) v).asInt()); + } else if (vt == PyLong.TYPE) { + write_byte(TYPE_LONG); + write_long(((PyLong) v).getValue()); + } else if (vt == PyFloat.TYPE) { + if (version == CURRENT_VERSION) { + write_byte(TYPE_BINARY_FLOAT); + write_binary_float((PyFloat) v); + } else { + write_byte(TYPE_FLOAT); + write_float((PyFloat) v); + } + } else if (vt == PyComplex.TYPE) { + PyComplex x = (PyComplex) v; + if (version == CURRENT_VERSION) { + write_byte(TYPE_BINARY_COMPLEX); + write_binary_float(x.getReal()); + write_binary_float(x.getImag()); + } else { + write_byte(TYPE_COMPLEX); + write_float(x.getReal()); + write_float(x.getImag()); + } + } else if (vt == PyUnicode.TYPE) { + write_byte(TYPE_UNICODE); + String buffer = ((PyUnicode) v).encode("utf-8").toString(); + write_int(buffer.length()); + write_string(buffer); + } else if (vt == PyString.TYPE) { + // ignore interning + write_byte(TYPE_STRING); + write_int(v.__len__()); + write_string(v.toString()); + } else if (vt == PyTuple.TYPE) { + write_byte(TYPE_TUPLE); + PyTuple t = (PyTuple) v; + int n = t.__len__(); + write_int(n); + for (int i = 0; i < n; i++) { + write_object(t.__getitem__(i), depth + 1); + } + } else if (vt == PyList.TYPE) { + write_byte(TYPE_LIST); + PyList list = (PyList) v; + int n = list.__len__(); + write_int(n); + for (int i = 0; i < n; i++) { + write_object(list.__getitem__(i), depth + 1); + } + } else if (vt == PyDictionary.TYPE) { + write_byte(TYPE_DICT); + PyDictionary dict = (PyDictionary) v; + for (PyObject item : dict.iteritems().asIterable()) { + PyTuple pair = (PyTuple) item; + write_object(pair.__getitem__(0), depth + 1); + write_object(pair.__getitem__(1), depth + 1); + } + write_object(null, depth + 1); + } else if (vt == PySet.TYPE || vt == PyFrozenSet.TYPE) { + if (vt == PySet.TYPE) { + write_byte(TYPE_SET); + } else { + write_byte(TYPE_FROZENSET); + } + int n = v.__len__(); + write_int(n); + BaseSet set = (BaseSet) v; + for (PyObject item : set.asIterable()) { + write_object(item, depth + 1); + } + } else if (vt == PyBytecode.TYPE) { + PyBytecode code = (PyBytecode) v; + write_byte(TYPE_CODE); + write_int(code.co_argcount); + write_int(code.co_nlocals); + write_int(code.co_stacksize); + write_int(code.co_flags.toBits()); + write_object(Py.newString(new String(code.co_code)), depth + 1); + write_object(new PyTuple(code.co_consts), depth + 1); + write_strings(code.co_names, depth + 1); + write_strings(code.co_varnames, depth + 1); + write_strings(code.co_freevars, depth + 1); + write_strings(code.co_cellvars, depth + 1); + write_object(Py.newString(code.co_name), depth + 1); + write_int(code.co_firstlineno); + write_object(Py.newString(new String(code.co_lnotab)), depth + 1); } else { - write_byte(TYPE_FROZENSET); - } - int n = v.__len__(); - write_int(n); - BaseSet set = (BaseSet) v; - for (PyObject item : set.asIterable()) { - write_object(item, depth + 1); + // Try to get a simple byte-oriented buffer + try (PyBuffer buf = ((BufferProtocol) v).getBuffer(PyBUF.SIMPLE)) { + // ... and treat those bytes as a String + write_byte(TYPE_STRING); + write_int(v.__len__()); + write_string(buf.toString()); + } catch (ClassCastException | PyException e) { + // Does not implement BufferProtocol (in simple byte form). + throw Py.ValueError("unmarshallable object"); + } } - } else if (v instanceof PyBytecode) { - PyBytecode code = (PyBytecode) v; - write_byte(TYPE_CODE); - write_int(code.co_argcount); - write_int(code.co_nlocals); - write_int(code.co_stacksize); - write_int(code.co_flags.toBits()); - write_object(Py.newString(new String(code.co_code)), depth + 1); - write_object(new PyTuple(code.co_consts), depth + 1); - write_strings(code.co_names, depth + 1); - write_strings(code.co_varnames, depth + 1); - write_strings(code.co_freevars, depth + 1); - write_strings(code.co_cellvars, depth + 1); - write_object(Py.newString(code.co_name), depth + 1); - write_int(code.co_firstlineno); - write_object(Py.newString(new String(code.co_lnotab)), depth + 1); - } else { - write_byte(TYPE_UNKNOWN); } - depth--; } @@ -329,21 +344,25 @@ private long read_long64() { // cpython calls this r_long64 } private BigInteger read_long() { - int size = read_int(); - int sign = 1; - if (size < 0) { - sign = -1; + BigInteger result = BigInteger.ZERO; + boolean negative = false; + int digit = 0, size = read_int(); + if (size == 0) { + return result; + } else if (size < 0) { + negative = true; size = -size; } - BigInteger result = BigInteger.ZERO; for (int i = 0; i < size; i++) { - String digits = String.valueOf(read_short()); - result = result.or(new BigInteger(digits).shiftLeft(i * 15)); + if ((digit = read_short()) < 0) { + throw badMarshalData("digit out of range in long"); + } + result = result.or(BigInteger.valueOf(digit).shiftLeft(i * 15)); } - if (sign < 0) { - result = result.negate(); + if (digit == 0) { + throw badMarshalData("unnormalized long data"); } - return result; + return negative ? result.negate() : result; } private double read_float() { @@ -358,7 +377,7 @@ private double read_binary_float() { private PyObject read_object_notnull(int depth) { PyObject v = read_object(depth); if (v == null) { - throw Py.ValueError("bad marshal data"); + throw badMarshalData(null); } return v; } @@ -453,7 +472,7 @@ private PyObject read_object(int depth) { case TYPE_TUPLE: { int n = read_int(); if (n < 0) { - throw Py.ValueError("bad marshal data"); + throw badMarshalData(null); } PyObject items[] = new PyObject[n]; for (int i = 0; i < n; i++) { @@ -465,7 +484,7 @@ private PyObject read_object(int depth) { case TYPE_LIST: { int n = read_int(); if (n < 0) { - throw Py.ValueError("bad marshal data"); + throw badMarshalData(null); } PyObject items[] = new PyObject[n]; for (int i = 0; i < n; i++) { @@ -530,10 +549,18 @@ private PyObject read_object(int depth) { } default: - throw Py.ValueError("bad marshal data"); + throw badMarshalData("unknown type code"); } } + /** Helper returning "bad marshal data" or "bad marshal data ()". */ + private static PyException badMarshalData(String reason) { + StringBuilder msg = (new StringBuilder(60)).append("bad marshal data"); + if (reason != null) { + msg.append(" (").append(reason).append(')'); + } + return Py.ValueError(msg.toString()); + } /* Traverseproc implementation */ @Override diff --git a/src/org/python/modules/_py_compile.java b/src/org/python/modules/_py_compile.java index 43b952066..43555cce8 100644 --- a/src/org/python/modules/_py_compile.java +++ b/src/org/python/modules/_py_compile.java @@ -12,22 +12,30 @@ public class _py_compile { public static PyList __all__ = new PyList(new PyString[] { new PyString("compile") }); - public static boolean compile(String filename, String cfile, String dfile) { - // Resolve relative path names. dfile is only used for error messages and should not be - // resolved + /** + * Java wrapper on the module compiler in support of of py_compile.compile. Filenames here will + * be interpreted as Unicode if they are PyUnicode, and as byte-encoded names if they only + * PyString. + * + * @param fileName actual source file name + * @param compiledName compiled filename + * @param displayName displayed source filename, only used for error messages (and not resolved) + * @return true if successful + */ + public static boolean compile(PyString fileName, PyString compiledName, PyString displayName) { + // Resolve source path and check it exists PySystemState sys = Py.getSystemState(); - filename = sys.getPath(filename); - cfile = sys.getPath(cfile); - - File file = new File(filename); - if (!file.exists()) { - throw Py.IOError(Errno.ENOENT, Py.newString(filename)); + String file = sys.getPath(Py.fileSystemDecode(fileName)); + File f = new File(file); + if (!f.exists()) { + throw Py.IOError(Errno.ENOENT, file); } - String name = getModuleName(file); - - byte[] bytes = org.python.core.imp.compileSource(name, file, dfile, cfile); - org.python.core.imp.cacheCompiledSource(filename, cfile, bytes); + // Convert file in which to put the byte code and display name (each may be null) + String c = (compiledName == null) ? null : sys.getPath(Py.fileSystemDecode(compiledName)); + String d = (displayName == null) ? null : Py.fileSystemDecode(displayName); + byte[] bytes = org.python.core.imp.compileSource(getModuleName(f), f, d); + org.python.core.imp.cacheCompiledSource(file, c, bytes); return bytes.length > 0; } diff --git a/src/org/python/modules/_systemrestart.java b/src/org/python/modules/_systemrestart.java deleted file mode 100644 index 187fb0773..000000000 --- a/src/org/python/modules/_systemrestart.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.python.modules; - -import org.python.core.ClassDictInit; -import org.python.core.Py; -import org.python.core.PyException; -import org.python.core.PyObject; -import org.python.core.PyStringMap; - -public class _systemrestart implements ClassDictInit { - /** - * Jython-specific exception for restarting the interpreter. Currently - * supported only by jython.java, when executing a file (i.e, - * non-interactive mode). - * - * WARNING: This is highly *experimental* and subject to change. - */ - public static PyObject SystemRestart; - - public static void classDictInit(PyObject dict) { - SystemRestart = Py.makeClass( - "_systemrestart.SystemRestart", Py.BaseException, - new PyStringMap() {{ - __setitem__("__doc__", - Py.newString("Request to restart the interpreter. " + - "(Jython-specific)")); - }}); - dict.__delitem__("classDictInit"); - } -} diff --git a/src/org/python/modules/_weakref/ReferenceTypeDerived.java b/src/org/python/modules/_weakref/ReferenceTypeDerived.java index d727c5596..5a2e8d2f7 100644 --- a/src/org/python/modules/_weakref/ReferenceTypeDerived.java +++ b/src/org/python/modules/_weakref/ReferenceTypeDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/binascii.java b/src/org/python/modules/binascii.java index 3758b4e8b..975e17c25 100644 --- a/src/org/python/modules/binascii.java +++ b/src/org/python/modules/binascii.java @@ -1,16 +1,14 @@ /* - * Copyright 1998 Finn Bock. + * Copyright 2019 Jython Developers * - * This program contains material copyrighted by: - * Copyright (c) 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum, - * Amsterdam, The Netherlands. + * Original conversion from CPython source copyright 1998 Finn Bock. + * + * This program contains material copyrighted by: Copyright (c) 1991, 1992, 1993, 1994 by Stichting + * Mathematisch Centrum, Amsterdam, The Netherlands. */ package org.python.modules; - -import java.util.regex.Pattern; - import org.python.core.ArgParser; import org.python.core.BufferProtocol; import org.python.core.Py; @@ -21,112 +19,75 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PyTuple; -import org.python.core.util.StringUtil; +import org.python.core.PyUnicode; +import org.python.core.buffer.SimpleStringBuffer; /** - * The binascii.java module contains a number of methods to convert - * between binary and various ASCII-encoded binary - * representations. Normally, you will not use these modules directly but - * use wrapper modules like uu or - * hexbin instead, this module solely - * exists because bit-manipuation of large amounts of data is slow in - * Python. + * The binascii.java module contains a number of methods to convert between binary and + * various ASCII-encoded binary representations. Normally, you will not use these modules directly + * but use wrapper modules like uu or hexbin instead, this module solely exists + * because bit-manipulation of large amounts of data is slow in Python. * *

    * The binascii.java module defines the following functions: - *

    - *

    a2b_uu (string) - *
    - * Convert a single line of uuencoded data back to binary and return the - * binary data. Lines normally contain 45 (binary) bytes, except for the - * last line. Line data may be followed by whitespace. - *
    * - *

    - *

    b2a_uu (data) - *
    - * Convert binary data to a line of ASCII characters, the return value - * is the converted line, including a newline char. The length of - * data should be at most 45. - *
    + *
    + *
    a2b_uu (string)
    + *
    Convert a single line of uuencoded data back to binary and return the binary data. Lines + * normally contain 45 (binary) bytes, except for the last line. Line data may be followed by + * whitespace.
    * - *

    - *

    a2b_base64 (string) - *
    - * Convert a block of base64 data back to binary and return the - * binary data. More than one line may be passed at a time. - *
    + *
    b2a_uu (data)
    + *
    Convert binary data to a line of ASCII characters, the return value is the converted line, + * including a newline char. The length of data should be at most 45.
    * - *

    - *

    b2a_base64 (data) - *
    - * Convert binary data to a line of ASCII characters in base64 coding. - * The return value is the converted line, including a newline char. - * The length of data should be at most 57 to adhere to the base64 - * standard. - *
    + *
    a2b_base64 (string)
    + *
    Convert a block of base64 data back to binary and return the binary data. More than one line + * may be passed at a time.
    * - *

    - *

    a2b_hqx (string) - *
    - * Convert binhex4 formatted ASCII data to binary, without doing - * RLE-decompression. The string should contain a complete number of - * binary bytes, or (in case of the last portion of the binhex4 data) - * have the remaining bits zero. - *
    + *
    b2a_base64 (data)
    + *
    Convert binary data to a line of ASCII characters in base64 coding. The return value is the + * converted line, including a newline char. The length of data should be at most 57 to + * adhere to the base64 standard.
    * - *

    - *

    rledecode_hqx (data) - *
    - * Perform RLE-decompression on the data, as per the binhex4 - * standard. The algorithm uses 0x90 after a byte as a repeat - * indicator, followed by a count. A count of 0 specifies a byte - * value of 0x90. The routine returns the decompressed data, - * unless data input data ends in an orphaned repeat indicator, in which - * case the Incomplete exception is raised. - *
    + *
    a2b_hqx (string)
    + *
    Convert binhex4 formatted ASCII data to binary, without doing RLE-decompression. The string + * should contain a complete number of binary bytes, or (in case of the last portion of the binhex4 + * data) have the remaining bits zero.
    * - *

    - *

    rlecode_hqx (data) - *
    - * Perform binhex4 style RLE-compression on data and return the - * result. - *
    + *
    rledecode_hqx (data)
    + *
    Perform RLE-decompression on the data, as per the binhex4 standard. The algorithm uses + * 0x90 after a byte as a repeat indicator, followed by a count. A count of 0 + * specifies a byte value of 0x90. The routine returns the decompressed data, unless data + * input data ends in an orphaned repeat indicator, in which case the Incomplete exception + * is raised.
    * - *

    - *

    b2a_hqx (data) - *
    - * Perform hexbin4 binary-to-ASCII translation and return the - * resulting string. The argument should already be RLE-coded, and have a - * length divisible by 3 (except possibly the last fragment). - *
    + *
    rlecode_hqx (data)
    + *
    Perform binhex4 style RLE-compression on data and return the result.
    * - *

    - *

    crc_hqx (data, crc) - *
    - * Compute the binhex4 crc value of data, starting with an initial - * crc and returning the result. - *
    + *
    b2a_hqx (data)
    + *
    Perform hexbin4 binary-to-ASCII translation and return the resulting string. The argument + * should already be RLE-coded, and have a length divisible by 3 (except possibly the last + * fragment).
    * - *
    Error - *
    - * Exception raised on errors. These are usually programming errors. - *
    + *
    crc_hqx (data, crc)
    + *
    Compute the binhex4 crc value of data, starting with an initial crc and + * returning the result.
    * - *

    - *

    Incomplete - *
    - * Exception raised on incomplete data. These are usually not programming - * errors, but may be handled by reading a little more data and trying - * again. + *
    Error
    + *
    Exception raised on errors. These are usually programming errors.
    + * + *
    Incomplete
    + *
    Exception raised on incomplete data. These are usually not programming errors, but may be + * handled by reading a little more data and trying again.
    *
    * - * The module is a line-by-line conversion of the original binasciimodule.c - * written by Jack Jansen, except that all mistakes and errors are my own. - *

    + * The module is a line-by-line conversion of the original binasciimodule.c written by Jack Jansen, + * except that all mistakes and errors are my own. + * * @author Finn Bock, bckfnn@pipmail.dknet.dk * @version binascii.java,v 1.6 1999/02/20 11:37:07 fb Exp - + * */ public class binascii { @@ -134,8 +95,8 @@ public class binascii { public static final PyObject Error = Py.makeClass("Error", Py.Exception, exceptionNamespace()); - public static final PyObject Incomplete = Py.makeClass("Incomplete", Py.Exception, - exceptionNamespace()); + public static final PyObject Incomplete = + Py.makeClass("Incomplete", Py.Exception, exceptionNamespace()); public static PyObject exceptionNamespace() { PyObject dict = new PyStringMap(); @@ -146,11 +107,12 @@ public static PyObject exceptionNamespace() { // hqx lookup table, ascii->binary. private static char RUNCHAR = 0x90; - private static short DONE = 0x7F; - private static short SKIP = 0x7E; - private static short FAIL = 0x7D; + private static byte DONE = 0x7F; + private static byte SKIP = 0x7E; + private static byte FAIL = 0x7D; - private static short[] table_a2b_hqx = { + //@formatter:off + private static byte[] table_a2b_hqx = { /* ^@ ^A ^B ^C ^D ^E ^F ^G */ /* 0*/ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, /* \b \t \n ^K ^L \r ^N ^O */ @@ -200,14 +162,13 @@ public static PyObject exceptionNamespace() { FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, }; + //@formatter:on - private static byte[] table_b2a_hqx = - StringUtil.toBytes("!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr"); - - + private static char[] table_b2a_hqx = + "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr".toCharArray(); - - private static short table_a2b_base64[] = { + //@formatter:off + private static byte table_a2b_base64[] = { -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, @@ -217,17 +178,17 @@ public static PyObject exceptionNamespace() { -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 }; + //@formatter:on private static char BASE64_PAD = '='; /* Max binary chunk size */ private static int BASE64_MAXBIN = Integer.MAX_VALUE / 2 - 3; - private static byte[] table_b2a_base64 = - StringUtil.toBytes("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"); - - + private static char[] table_b2a_base64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray(); + //@formatter:off private static int[] crctab_hqx = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, @@ -262,806 +223,750 @@ public static PyObject exceptionNamespace() { 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0, }; + //@formatter:on - - - public static PyString __doc__a2b_uu = new PyString( - "(ascii) -> bin. Decode a line of uuencoded data" - ); - + public static PyString __doc__a2b_uu = + new PyString("(ascii) -> bin. Decode a line of uuencoded data"); /** - * Convert a single line of uuencoded data back to binary and return the - * binary data. Lines normally contain 45 (binary) bytes, except for the - * last line. Line data may be followed by whitespace. + * Convert a single line of uuencoded data back to binary and return the binary data. Lines + * normally contain 45 (binary) bytes, except for the last line. Line data may be followed by + * whitespace. */ - public static PyString a2b_uu(BufferProtocol bp) { - int leftbits = 0; - int leftchar = 0; + public static PyString a2b_uu(PyObject text) { - StringBuilder bin_data = new StringBuilder(); - PyBuffer ascii_data = bp.getBuffer(PyBUF.SIMPLE); - try { - if (ascii_data.getLen() == 0) + try (PyBuffer textBuf = getByteBuffer(text)) { + int textLen = textBuf.getLen(); + if (textLen == 0) { return new PyString(""); + } + StringBuilder dataBuf = new StringBuilder(); - char this_ch; - int i; + int bits = 0; // store bits not yet emitted (max 12 bits) + int bitCount = 0; // how many (valid) bits waiting + int index = 0; - int ascii_len = ascii_data.getLen()-1; + int dataExpected = (textBuf.intAt(0) - ' ') & 077; + textLen -= 1; - int bin_len = (ascii_data.intAt(0) - ' ') & 077; + for (; dataExpected > 0 && textLen > 0; index++, textLen--) { + int ch = textBuf.intAt(index + 1); + int sixBits; - for (i = 0; bin_len > 0 && ascii_len > 0; i++, ascii_len--) { - this_ch = (char) ascii_data.intAt(i+1); - if (this_ch == '\n' || this_ch == '\r' || ascii_len <= 0) { - // Whitespace. Assume some spaces got eaten at - // end-of-line. (We check this later) - this_ch = 0; + if (ch == '\n' || ch == '\r' || textLen <= 0) { + // Whitespace. Assume some spaces got eaten at end-of-line. + // (We check this later.) + sixBits = 0; } else { - // Check the character for legality - // The 64 in stead of the expected 63 is because - // there are a few uuencodes out there that use - // '@' as zero instead of space. - if ( this_ch < ' ' || this_ch > (' ' + 64)) { + /* + * Check the character for legality The 64 instead of the expected 63 is because + * there are a few uuencodes out there that use '@' as zero instead of space. + */ + if (ch < ' ' || ch > (' ' + 64)) { throw new PyException(Error, "Illegal char"); } - this_ch = (char)((this_ch - ' ') & 077); + sixBits = (ch - ' ') & 0x3f; } - // Shift it in on the low end, and see if there's - // a byte ready for output. - leftchar = (leftchar << 6) | (this_ch); - leftbits += 6; - if (leftbits >= 8) { - leftbits -= 8; - bin_data.append((char)((leftchar >> leftbits) & 0xff)); - leftchar &= ((1 << leftbits) - 1); - bin_len--; + + // Shift it in on the low end, and see if there's a byte ready for output. + bits = (bits << 6) | sixBits; + bitCount += 6; + if (bitCount >= 8) { + bitCount -= 8; + int b = (bits >> bitCount) & 0xff; + dataBuf.append((char) b); // byte + bits &= (1 << bitCount) - 1; + dataExpected--; } } - // Finally, check that if there's anything left on the line - // that it's whitespace only. - while (ascii_len-- > 0) { - this_ch = (char) ascii_data.intAt(++i); + // Finally, check that anything left on the line is white space. + while (textLen-- > 0) { + int ch = textBuf.intAt(++index); // Extra '@' may be written as padding in some cases - if (this_ch != ' ' && this_ch != '@' && - this_ch != '\n' && this_ch != '\r') { + if (ch != ' ' && ch != '@' && ch != '\n' && ch != '\r') { throw new PyException(Error, "Trailing garbage"); } } - - // finally, if we haven't decoded enough stuff, fill it up with zeros - for (; i ascii. Uuencode line of data" - ); + } catch (ClassCastException e) { + throw argMustBeBytes("a2b_uu", text); + } + } + public static PyString __doc__b2a_uu = new PyString("(bin) -> ascii. Uuencode line of data"); /** - * Convert binary data to a line of ASCII characters, the return value - * is the converted line, including a newline char. The length of - * data should be at most 45. + * Convert binary data to a line of ASCII characters, the return value is the converted line, + * including a newline char. The length of data should be at most 45. */ - public static PyString b2a_uu(BufferProtocol bp) { - int leftbits = 0; - char this_ch; - int leftchar = 0; + public static PyString b2a_uu(PyObject data) { - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); + try (PyBuffer dataBuf = getByteBuffer(data)) { - StringBuilder ascii_data = new StringBuilder(); - try { - int bin_len = bin_data.getLen(); - if (bin_len > 45) { + int dataLen = dataBuf.getLen(); + if (dataLen > 45) { // The 45 is a limit that appears in all uuencode's throw new PyException(Error, "At most 45 bytes at once"); } - // Store the length */ - ascii_data.append((char)(' ' + (bin_len & 077))); + // Each 3 bytes (rounded up) produce 4 characters, plus a 1 byte length and '\n' + StringBuilder textBuf = new StringBuilder(4 * ((dataLen + 2) / 3) + 2); + int bitCount = 0; + int bits = 0; + + // Store the length + textBuf.append((char) (' ' + (dataLen & 077))); - for (int i = 0; bin_len > 0 || leftbits != 0; i++, bin_len--) { + for (int i = 0; dataLen > 0 || bitCount != 0; i++, dataLen--) { // Shift the data (or padding) into our buffer - if (bin_len > 0) // Data - leftchar = (leftchar << 8) | (char) bin_data.intAt(i); - else // Padding - leftchar <<= 8; - leftbits += 8; + if (dataLen > 0) { + bits = (bits << 8) | dataBuf.intAt(i); + } else { + bits <<= 8; + } + bitCount += 8; // See if there are 6-bit groups ready - while (leftbits >= 6) { - this_ch = (char)((leftchar >> (leftbits-6)) & 0x3f); - leftbits -= 6; - ascii_data.append((char)(this_ch + ' ')); + while (bitCount >= 6) { + bitCount -= 6; + int sixBits = (bits >> bitCount) & 0x3f; + textBuf.append((char) (sixBits + ' ')); } } - } finally { - bin_data.release(); - } - ascii_data.append('\n'); // Append a courtesy newline - return new PyString(ascii_data.toString()); - } + textBuf.append('\n'); // Append a courtesy newline + return new PyString(textBuf.toString()); + } catch (ClassCastException e) { + throw argMustBeBytes("b2a_uu", data); + } + } + /** Finds & returns the (num+1)th valid character for base64, or -1 if none. */ private static int binascii_find_valid(PyBuffer b, int offset, int num) { int blen = b.getLen() - offset; - - /* Finds & returns the (num+1)th - ** valid character for base64, or -1 if none. - */ - int ret = -1; while ((blen > 0) && (ret == -1)) { int c = b.intAt(offset); - short b64val = table_a2b_base64[c & 0x7f]; - if (((c <= 0x7f) && (b64val != -1)) ) { - if (num == 0) - ret = c; + byte b64val = table_a2b_base64[c & 0x7f]; + if (((c <= 0x7f) && (b64val != -1))) { + if (num == 0) { + ret = c; + } num--; } - offset++; blen--; } return ret; } - - - public static PyString __doc__a2b_base64 = new PyString( - "(ascii) -> bin. Decode a line of base64 data" - ); + public static PyString __doc__a2b_base64 = + new PyString("(ascii) -> bin. Decode a line of base64 data"); /** - * Convert a block of base64 data back to binary and return the - * binary data. More than one line may be passed at a time. + * Convert a block of base64 data back to binary and return the binary data. More than one line + * may be passed at a time. */ - public static PyString a2b_base64(BufferProtocol bp) { - int leftbits = 0; - char this_ch; - int leftchar = 0; - int quad_pos = 0; + public static PyString a2b_base64(PyObject text) { - PyBuffer ascii_data = bp.getBuffer(PyBUF.SIMPLE); - int ascii_len = ascii_data.getLen(); + try (PyBuffer textBuf = getByteBuffer(text)) { + int textLen = textBuf.getLen(); - int bin_len = 0; - StringBuilder bin_data = new StringBuilder(); + // Every 4 characters (rounded up) map to 3 bytes. (Or fewer, if there are extras.) + int dataLen = 3 * ((textLen + 3) / 4); + // These characters will represent bytes, in the usual Jython 2 way. + StringBuilder dataBuf = new StringBuilder(dataLen); + int bits = 0; // store bits not yet emitted (max 12 bits) + int bitCount = 0; // how many (valid) bits waiting + int quad_pos = 0; - try { - for(int i = 0; ascii_len > 0 ; ascii_len--, i++) { + for (int i = 0; textLen > 0; textLen--, i++) { // Skip some punctuation - this_ch = (char) ascii_data.intAt(i); - if (this_ch > 0x7F || this_ch == '\r' || - this_ch == '\n' || this_ch == ' ') + int ch = textBuf.intAt(i); + if (ch > 0x7F || ch == '\r' || ch == '\n' || ch == ' ') { continue; - if (this_ch == BASE64_PAD) { - if (quad_pos < 2 || (quad_pos == 2 && - binascii_find_valid(ascii_data, i, 1) != BASE64_PAD)) + } else + + if (ch == BASE64_PAD) { + if (quad_pos < 2 || (quad_pos == 2 + && binascii_find_valid(textBuf, i, 1) != BASE64_PAD)) { continue; - else { - // A pad sequence means no more input. - // We've already interpreted the data + } else { + // A pad sequence means no more input. We've already interpreted the data // from the quad at this point. - leftbits = 0; + bitCount = 0; break; } - } + } else { - short this_v = table_a2b_base64[this_ch]; - if (this_v == -1) - continue; + int sixBits = table_a2b_base64[ch]; + if (sixBits == -1) { + continue; + } - // Shift it in on the low end, and see if there's - // a byte ready for output. - quad_pos = (quad_pos + 1) & 0x03; - leftchar = (leftchar << 6) | (this_v); - leftbits += 6; - if (leftbits >= 8) { - leftbits -= 8; - bin_data.append((char)((leftchar >> leftbits) & 0xff)); - bin_len++; - leftchar &= ((1 << leftbits) - 1); + // Shift it in on the low end, and see if there's a byte ready for output. + quad_pos = (quad_pos + 1) & 0x03; + bits = (bits << 6) | sixBits; + bitCount += 6; + if (bitCount >= 8) { + bitCount -= 8; + dataBuf.append((char) ((bits >> bitCount) & 0xff)); // byte + // Erase the bits we emitted + bits &= (1 << bitCount) - 1; + } } } - } finally { - ascii_data.release(); - } - // Check that no bits are left - if (leftbits != 0) { - throw new PyException(Error, "Incorrect padding"); - } - return new PyString(bin_data.toString()); - } - + // Check that no bits are left + if (bitCount != 0) { + throw new PyException(Error, "Incorrect padding"); + } + return new PyString(dataBuf.toString()); - public static PyString __doc__b2a_base64 = new PyString( - "(bin) -> ascii. Base64-code line of data" - ); + } catch (ClassCastException e) { + throw argMustBeBytes("a2b_base64", text); + } + } + public static PyString __doc__b2a_base64 = + new PyString("(bin) -> ascii. Base64-code line of data"); /** - * Convert binary data to a line of ASCII characters in base64 coding. - * The return value is the converted line, including a newline char. + * Convert binary data to a line of ASCII characters in base64 coding. The return value is the + * converted line, including a newline char. */ - public static PyString b2a_base64(BufferProtocol bp) { - int leftbits = 0; - char this_ch; - int leftchar = 0; + public static PyString b2a_base64(PyObject data) { - StringBuilder ascii_data = new StringBuilder(); - - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); - try { - int bin_len = bin_data.getLen(); - if (bin_len > BASE64_MAXBIN) { - throw new PyException(Error,"Too much data for base64 line"); + try (PyBuffer dataBuf = getByteBuffer(data)) { + int dataLen = dataBuf.getLen(); + if (dataLen > BASE64_MAXBIN) { + throw new PyException(Error, "Too much data for base64 line"); } + // Every 3 bytes (rounded up) maps to 4 characters (and there's a newline) + StringBuilder ascii_data = new StringBuilder(4 * ((dataLen + 2) / 3) + 1); + int bits = 0; // store bits not yet emitted (max 14 bits) + int bitCount = 0; // how many (valid) bits waiting - for (int i = 0; bin_len > 0 ; bin_len--, i++) { + for (int i = 0; i < dataLen; i++) { // Shift the data into our buffer - leftchar = (leftchar << 8) | (char) bin_data.intAt(i); //charAt(i); - leftbits += 8; + bits = (bits << 8) | dataBuf.intAt(i); + bitCount += 8; - // See if there are 6-bit groups ready - while (leftbits >= 6) { - this_ch = (char)((leftchar >> (leftbits-6)) & 0x3f); - leftbits -= 6; - ascii_data.append((char)table_b2a_base64[this_ch]); + // While there are 6-bit groups available, emit them as characters. + while (bitCount >= 6) { + bitCount -= 6; + ascii_data.append(table_b2a_base64[(bits >> bitCount) & 0x3f]); } } - } finally { - bin_data.release(); - } - if (leftbits == 2) { - ascii_data.append((char)table_b2a_base64[(leftchar&3) << 4]); - ascii_data.append(BASE64_PAD); - ascii_data.append(BASE64_PAD); - } else if (leftbits == 4) { - ascii_data.append((char)table_b2a_base64[(leftchar&0xf) << 2]); - ascii_data.append(BASE64_PAD); - } - ascii_data.append('\n'); // Append a courtesy newline - return new PyString(ascii_data.toString()); - } + // Emit the balance of bits and append a newline + if (bitCount == 2) { + ascii_data.append(table_b2a_base64[(bits & 3) << 4]); + ascii_data.append(BASE64_PAD); + ascii_data.append(BASE64_PAD); + } else if (bitCount == 4) { + ascii_data.append(table_b2a_base64[(bits & 0xf) << 2]); + ascii_data.append(BASE64_PAD); + } + ascii_data.append('\n'); // Append a courtesy newline + + return new PyString(ascii_data.toString()); + } catch (ClassCastException e) { + throw argMustBeBytes("b2a_base64", data); + } + } - public static PyString __doc__a2b_hqx = new PyString( - "ascii -> bin, done. Decode .hqx coding" - ); + public static PyString __doc__a2b_hqx = new PyString("ascii -> bin, done. Decode .hqx coding"); /** - * Convert binhex4 formatted ASCII data to binary, without doing - * RLE-decompression. The string should contain a complete number of - * binary bytes, or (in case of the last portion of the binhex4 data) - * have the remaining bits zero. + * Convert binhex4 formatted ASCII data to binary, without doing RLE-decompression. The string + * should contain a complete number of binary bytes, or (in case of the last portion of the + * binhex4 data) have the remaining bits zero. */ - public static PyTuple a2b_hqx(BufferProtocol bp) { - int leftbits = 0; - char this_ch; - int leftchar = 0; + public static PyTuple a2b_hqx(PyObject text) { - boolean done = false; - PyBuffer ascii_data = bp.getBuffer(PyBUF.SIMPLE); - int len = ascii_data.getLen(); + try (PyBuffer textBuf = getByteBuffer(text)) { - StringBuilder bin_data = new StringBuilder(); + int textLen = textBuf.getLen(); + StringBuilder dataBuf = new StringBuilder(); + int bitCount = 0; + int bits = 0; + boolean done = false; - try { - for(int i = 0; len > 0 ; len--, i++) { + for (int i = 0; i < textLen; i++) { // Get the byte and look it up - this_ch = (char) table_a2b_hqx[ascii_data.intAt(i)]; - if (this_ch == SKIP) + byte b = table_a2b_hqx[textBuf.intAt(i)]; + + if (b == SKIP) { continue; - if (this_ch == FAIL) { + + } else if (b == FAIL) { throw new PyException(Error, "Illegal char"); - } - if (this_ch == DONE) { + + } else if (b == DONE) { // The terminating colon done = true; break; - } - // Shift it into the buffer and see if any bytes are ready - leftchar = (leftchar << 6) | (this_ch); - leftbits += 6; - if (leftbits >= 8) { - leftbits -= 8; - bin_data.append((char)((leftchar >> leftbits) & 0xff)); - leftchar &= ((1 << leftbits) - 1); + } else { + // Shift it into the buffer and see if any bytes are ready + bits = (bits << 6) | b; + bitCount += 6; + if (bitCount >= 8) { + bitCount -= 8; + dataBuf.append((char) ((bits >> bitCount) & 0xff)); // byte + bits &= (1 << bitCount) - 1; + } } } - } finally { - ascii_data.release(); - } - if (leftbits != 0 && !done) { - throw new PyException(Incomplete, - "String has incomplete number of bytes"); - } + if (bitCount != 0 && !done) { + throw new PyException(Incomplete, "String has incomplete number of bytes"); + } - return new PyTuple(new PyString(bin_data.toString()), Py.newInteger(done ? 1 : 0)); + return new PyTuple(new PyString(dataBuf.toString()), Py.newInteger(done ? 1 : 0)); + + } catch (ClassCastException e) { + throw argMustBeBytes("a2b_hqx", text); + } } + public static PyString __doc__rlecode_hqx = new PyString("Binhex RLE-code binary data"); - public static PyString __doc__rlecode_hqx = new PyString( - "Binhex RLE-code binary data" - ); + /** Perform binhex4 style RLE-compression on data and return the result. */ + static public PyString rlecode_hqx(PyObject data) { - /** - * Perform binhex4 style RLE-compression on data and return the - * result. - */ - static public PyString rlecode_hqx(BufferProtocol bp) { - PyBuffer in_data = bp.getBuffer(PyBUF.SIMPLE); - int len = in_data.getLen(); + try (PyBuffer inBuf = getByteBuffer(data)) { + int len = inBuf.getLen(); + StringBuilder outBuf = new StringBuilder(); - StringBuilder out_data = new StringBuilder(); + for (int in = 0; in < len; in++) { + char ch = (char) inBuf.intAt(in); - try { - for (int in=0; in < len; in++) { - char ch = (char) in_data.intAt(in); if (ch == RUNCHAR) { // RUNCHAR. Escape it. - out_data.append(RUNCHAR); - out_data.append((char) 0); + outBuf.append(RUNCHAR); + outBuf.append((char) 0); + } else { // Check how many following are the same int inend; - for (inend=in+1; inend < len && - (char) in_data.intAt(inend) == ch && - inend < in+255; inend++) - ; + for (inend = in + 1; inend < len && ((char) inBuf.intAt(inend)) == ch + && inend < in + 255; inend++) { /* nothing */ } if (inend - in > 3) { // More than 3 in a row. Output RLE. - out_data.append(ch); - out_data.append(RUNCHAR); - out_data.append((char) (inend-in)); - in = inend-1; + outBuf.append(ch); + outBuf.append(RUNCHAR); + outBuf.append((char) (inend - in)); + in = inend - 1; } else { // Less than 3. Output the byte itself - out_data.append(ch); + outBuf.append(ch); } } } - } finally { - in_data.release(); + + return new PyString(outBuf.toString()); + + } catch (ClassCastException e) { + throw argMustBeBytes("rlecode_hqx", data); } - return new PyString(out_data.toString()); } - - public static PyString __doc__b2a_hqx = new PyString( - "Encode .hqx data" - ); + public static PyString __doc__b2a_hqx = new PyString("Encode .hqx data"); /** - * Perform hexbin4 binary-to-ASCII translation and return the - * resulting string. The argument should already be RLE-coded, and have a - * length divisible by 3 (except possibly the last fragment). + * Perform hexbin4 binary-to-ASCII translation and return the resulting string. The argument + * should already be RLE-coded, and have a length divisible by 3 (except possibly the last + * fragment). */ - public static PyString b2a_hqx(BufferProtocol bp) { - int leftbits = 0; - char this_ch; - int leftchar = 0; + public static PyString b2a_hqx(PyObject data) { - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); - int len = bin_data.getLen(); + try (PyBuffer dataBuf = getByteBuffer(data)) { + int len = dataBuf.getLen(); - StringBuilder ascii_data = new StringBuilder(); + StringBuilder textBuf = new StringBuilder(); + int bits = 0; + int bitCount = 0; - try { - for(int i = 0; len > 0; len--, i++) { + for (int i = 0; len > 0; len--, i++) { // Shift into our buffer, and output any 6bits ready - leftchar = (leftchar << 8) | (char) bin_data.intAt(i); - leftbits += 8; - while (leftbits >= 6) { - this_ch = (char) ((leftchar >> (leftbits-6)) & 0x3f); - leftbits -= 6; - ascii_data.append((char) table_b2a_hqx[this_ch]); + bits = (bits << 8) | (char) dataBuf.intAt(i); + bitCount += 8; + while (bitCount >= 6) { + bitCount -= 6; + textBuf.append(table_b2a_hqx[(bits >> bitCount) & 0x3f]); } } - } finally { - bin_data.release(); - } - - // Output a possible runt byte - if (leftbits != 0) { - leftchar <<= (6-leftbits); - ascii_data.append((char) table_b2a_hqx[leftchar & 0x3f]); - } - return new PyString(ascii_data.toString()); - } + // Output a possible runt byte + if (bitCount != 0) { + bits <<= (6 - bitCount); + textBuf.append(table_b2a_hqx[bits & 0x3f]); + } + return new PyString(textBuf.toString()); - public static PyString __doc__rledecode_hqx = new PyString( - "Decode hexbin RLE-coded string" - ); + } catch (ClassCastException e) { + throw argMustBeBytes("b2a_hqx", data); + } + } + public static PyString __doc__rledecode_hqx = new PyString("Decode hexbin RLE-coded string"); /** - * Perform RLE-decompression on the data, as per the binhex4 - * standard. The algorithm uses 0x90 after a byte as a repeat - * indicator, followed by a count. A count of 0 specifies a byte - * value of 0x90. The routine returns the decompressed data, - * unless data input data ends in an orphaned repeat indicator, in which - * case the Incomplete exception is raised. + * Perform RLE-decompression on the data, as per the binhex4 standard. The algorithm uses + * 0x90 after a byte as a repeat indicator, followed by a count. A count of 0 + * specifies a byte value of 0x90. The routine returns the decompressed data, unless + * data input data ends in an orphaned repeat indicator, in which case the Incomplete + * exception is raised. */ - static public PyString rledecode_hqx(BufferProtocol bp) { - char in_byte, in_repeat; - - PyBuffer in_data = bp.getBuffer(PyBUF.SIMPLE); - int in_len = in_data.getLen(); - int i = 0; - - StringBuilder out_data = new StringBuilder(); - try { + static public PyString rledecode_hqx(PyObject data) { + + try (PyBuffer inBuf = getByteBuffer(data)) { + int inLen = inBuf.getLen(); + int index = 0; + // Empty string is a special case - if (in_len == 0) + if (inLen == 0) { return Py.EmptyString; + } + // Pretty much throughout, we use a char to store a byte :( + StringBuilder outBuf = new StringBuilder(); // Handle first byte separately (since we have to get angry // in case of an orphaned RLE code). - if (--in_len < 0) throw new PyException(Incomplete); - in_byte = (char) in_data.intAt(i++); + if (--inLen < 0) { + throw new PyException(Incomplete); + } + char outByte = (char) inBuf.intAt(index++); - if (in_byte == RUNCHAR) { - if (--in_len < 0) throw new PyException(Incomplete); - in_repeat = (char) in_data.intAt(i++); + if (outByte == RUNCHAR) { + if (--inLen < 0) { + throw new PyException(Incomplete); + } + int in_repeat = inBuf.intAt(index++); if (in_repeat != 0) { // Note Error, not Incomplete (which is at the end // of the string only). This is a programmer error. throw new PyException(Error, "Orphaned RLE code at start"); } - out_data.append(RUNCHAR); + outBuf.append(RUNCHAR); } else { - out_data.append(in_byte); + outBuf.append(outByte); } - while (in_len > 0) { - if (--in_len < 0) throw new PyException(Incomplete); - in_byte = (char) in_data.intAt(i++); + while (inLen > 0) { + if (--inLen < 0) { + throw new PyException(Incomplete); + } + outByte = (char) inBuf.intAt(index++); - if (in_byte == RUNCHAR) { - if (--in_len < 0) throw new PyException(Incomplete); - in_repeat = (char) in_data.intAt(i++); + if (outByte == RUNCHAR) { + if (--inLen < 0) { + throw new PyException(Incomplete); + } + int in_repeat = inBuf.intAt(index++); if (in_repeat == 0) { // Just an escaped RUNCHAR value - out_data.append(RUNCHAR); + outBuf.append(RUNCHAR); } else { // Pick up value and output a sequence of it - in_byte = out_data.charAt(out_data.length()-1); - while (--in_repeat > 0) - out_data.append(in_byte); + outByte = outBuf.charAt(outBuf.length() - 1); + while (--in_repeat > 0) { + outBuf.append(outByte); + } } } else { // Normal byte - out_data.append(in_byte); + outBuf.append(outByte); } } - } finally { - in_data.release(); - } - return new PyString(out_data.toString()); - } + return new PyString(outBuf.toString()); + } catch (ClassCastException e) { + throw argMustBeBytes("rledecode_hqx", data); + } + } - public static PyString __doc__crc_hqx = new PyString( - "(data, oldcrc) -> newcrc. Compute hqx CRC incrementally" - ); - + public static PyString __doc__crc_hqx = + new PyString("(data, oldcrc) -> newcrc. Compute hqx CRC incrementally"); /** - * Compute the binhex4 crc value of data, starting with an initial - * crc and returning the result. + * Compute the binhex4 crc value of data, starting with an initial crc and + * returning the result. */ - public static int crc_hqx(BufferProtocol bp, int crc) { - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); - int len = bin_data.getLen(); - int i = 0; - - try { - while(len-- > 0) { - crc=((crc<<8)&0xff00) ^ - crctab_hqx[((crc>>8)&0xff)^ (char) bin_data.intAt(i++)]; + public static int crc_hqx(PyObject data, int crc) { + try (PyBuffer buf = getByteBuffer(data)) { + int len = buf.getLen(); + for (int i = 0; i < len; i++) { + crc = ((crc << 8) & 0xff00) ^ crctab_hqx[((crc >> 8) & 0xff) ^ buf.intAt(i)]; } - } finally { - bin_data.release(); + return crc; + } catch (ClassCastException e) { + throw argMustBeBytes("crc_hqx", data); } - - return crc; } + //@formatter:off + static int[] crc_32_tab = new int[] { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + //@formatter:on - - -static long[] crc_32_tab = new long[] { -0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -0x2d02ef8dL -}; - - public static int crc32(BufferProtocol bp) { + public static int crc32(PyObject bp) { return crc32(bp, 0); } - public static int crc32(BufferProtocol bp, long crc) { - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); - int len = bin_data.getLen(); + public static int crc32(PyObject data, long long_crc) { - crc &= 0xFFFFFFFFL; - crc = crc ^ 0xFFFFFFFFL; - try { + int crc = ~(int) long_crc; + + try (PyBuffer dataBuf = getByteBuffer(data)) { + int len = dataBuf.getLen(); for (int i = 0; i < len; i++) { - char ch = (char) bin_data.intAt(i); - crc = (int)crc_32_tab[(int) ((crc ^ ch) & 0xffL)] ^ (crc >> 8); - /* Note: (crc >> 8) MUST zero fill on left */ - crc &= 0xFFFFFFFFL; + int b = dataBuf.intAt(i); + crc = crc_32_tab[(crc ^ b) & 0xff] ^ (crc >>> 8); + /* Note: (crc >> 8) MUST zero fill on left */ } - } finally { - bin_data.release(); + return ~crc; + + } catch (ClassCastException e) { + throw argMustBeBytes("crc32", data); } - if (crc >= 0x80000000) - return -(int)(crc+1 & 0xFFFFFFFF); - else - return (int)(crc & 0xFFFFFFFF); - } + } private static char[] hexdigit = "0123456789abcdef".toCharArray(); - public static PyString __doc__b2a_hex = new PyString( - "b2a_hex(data) -> s; Hexadecimal representation of binary data.\n" + - "\n" + - "This function is also available as \"hexlify()\"." - ); + public static PyString __doc__b2a_hex = + new PyString("b2a_hex(data) -> s; Hexadecimal representation of binary data.\n" + "\n" + + "This function is also available as \"hexlify()\"."); - public static PyString b2a_hex(BufferProtocol bp) { - PyBuffer argbuf = bp.getBuffer(PyBUF.SIMPLE); - int arglen = argbuf.getLen(); + public static PyString b2a_hex(PyObject data) { - StringBuilder retbuf = new StringBuilder(arglen*2); + try (PyBuffer dataBuf = getByteBuffer(data)) { - try { - /* make hex version of string, taken from shamodule.c */ - for (int i = 0; i < arglen; i++) { - char ch = (char) argbuf.intAt(i); + int dataLen = dataBuf.getLen(); + StringBuilder retbuf = new StringBuilder(dataLen * 2); + + // make hex version of string, taken from shamodule.c + for (int i = 0; i < dataLen; i++) { + int ch = dataBuf.intAt(i); retbuf.append(hexdigit[(ch >>> 4) & 0xF]); retbuf.append(hexdigit[ch & 0xF]); } - } finally { - argbuf.release(); + + return new PyString(retbuf.toString()); + + } catch (ClassCastException e) { + throw argMustBeBytes("b2a_hex", data); } - return new PyString(retbuf.toString()); } - - public static PyString hexlify(BufferProtocol argbuf) { + public static PyString hexlify(PyObject argbuf) { return b2a_hex(argbuf); } + public static PyString a2b_hex$doc = + new PyString("a2b_hex(hexstr) -> s; Binary data of hexadecimal representation.\n" + "\n" + + "hexstr must contain an even number of hex digits " + + "(upper or lower case).\n" + + "This function is also available as \"unhexlify()\""); - public static PyString a2b_hex$doc = new PyString( - "a2b_hex(hexstr) -> s; Binary data of hexadecimal representation.\n" + - "\n" + - "hexstr must contain an even number of hex digits "+ - "(upper or lower case).\n"+ - "This function is also available as \"unhexlify()\"" - ); - + public static PyString a2b_hex(PyObject hexstr) { - public static PyString a2b_hex(BufferProtocol bp) { - PyBuffer argbuf = bp.getBuffer(PyBUF.SIMPLE); - int arglen = argbuf.getLen(); + try (PyBuffer buf = getByteBuffer(hexstr)) { - StringBuilder retbuf = new StringBuilder(arglen/2); - /* XXX What should we do about strings with an odd length? Should - * we add an implicit leading zero, or a trailing zero? For now, - * raise an exception. - */ - try { - if (arglen % 2 != 0) + int bufLen = buf.getLen(); + StringBuilder retbuf = new StringBuilder(bufLen / 2); + /* + * XXX What should we do about strings with an odd length? Should we add an implicit + * leading zero, or a trailing zero? For now, raise an exception. + */ + if (bufLen % 2 != 0) { throw Py.TypeError("Odd-length string"); + } - for (int i = 0; i < arglen; i += 2) { - int top = Character.digit(argbuf.intAt(i), 16); - int bot = Character.digit(argbuf.intAt(i+1), 16); - if (top == -1 || bot == -1) + for (int i = 0; i < bufLen; i += 2) { + int top = Character.digit(buf.intAt(i), 16); + int bot = Character.digit(buf.intAt(i + 1), 16); + if (top == -1 || bot == -1) { throw Py.TypeError("Non-hexadecimal digit found"); + } retbuf.append((char) ((top << 4) + bot)); } - } finally { - argbuf.release(); + + return new PyString(retbuf.toString()); + + } catch (ClassCastException e) { + throw argMustBeBytes("a2b_hex", hexstr); } - return new PyString(retbuf.toString()); } - - public static PyString unhexlify(BufferProtocol argbuf) { + public static PyString unhexlify(PyObject argbuf) { return a2b_hex(argbuf); } final private static char[] upper_hexdigit = "0123456789ABCDEF".toCharArray(); - - private static StringBuilder qpEscape(StringBuilder sb, char c) - { - sb.append('='); + + private static StringBuilder qpEscape(StringBuilder sb, char c) { + sb.append('='); sb.append(upper_hexdigit[(c >>> 4) & 0xF]); sb.append(upper_hexdigit[c & 0xF]); return sb; } - final private static Pattern UNDERSCORE = Pattern.compile("_"); - final public static PyString __doc__a2b_qp = new PyString("Decode a string of qp-encoded data"); - public static boolean getIntFlagAsBool(ArgParser ap, int index, int dflt, String errMsg) { - boolean val; + private static boolean getIntFlagAsBool(ArgParser ap, int index, int dflt, String errMsg) { try { - val = ap.getInt(index, dflt) != 0; + boolean val = ap.getInt(index, dflt) != 0; + return val; } catch (PyException e) { - if (e.match(Py.AttributeError) || e.match(Py.ValueError)) - throw Py.TypeError(errMsg); - throw e; + if (e.match(Py.AttributeError) || e.match(Py.ValueError)) { + throw Py.TypeError(errMsg); + } + throw e; } - return val; } - public static PyString a2b_qp(PyObject[] arg, String[] kws) - { + public static PyString a2b_qp(PyObject[] arg, String[] kws) { ArgParser ap = new ArgParser("a2b_qp", arg, kws, new String[] {"s", "header"}); - PyObject pyObject = ap.getPyObject(0); - BufferProtocol bp; - if (pyObject instanceof BufferProtocol) { - bp = (BufferProtocol) pyObject; - } else { - throw Py.TypeError("expected something conforming to the buffer protocol, got " - + pyObject.getType().fastGetName()); - } + PyObject bp = ap.getPyObject(0); StringBuilder sb = new StringBuilder(); boolean header = getIntFlagAsBool(ap, 1, 0, "an integer is required"); - PyBuffer ascii_data = bp.getBuffer(PyBUF.SIMPLE); - try { - for (int i=0, m=ascii_data.getLen(); i= '0' && c <= '9' || c >= 'A' && c <= 'F') && i < m) { + char nc = (char) ascii_data.intAt(i++); + if ((nc >= '0' && nc <= '9' || nc >= 'A' && nc <= 'F')) { + sb.append((char) (Character.digit(c, 16) << 4 + | Character.digit(nc, 16))); + } else { + sb.append('=').append(c).append(nc); + } + } else if (c != '\n') { + sb.append('=').append(c); + } } + } else { + sb.append(c); + } } - } finally { - ascii_data.release(); + return new PyString(sb.toString()); + } catch (ClassCastException e) { + throw argMustBeBytes("a2b_qp", bp); } - return new PyString(sb.toString()); } - final private static Pattern RN_TO_N = Pattern.compile("\r\n"); - final private static Pattern N_TO_RN = Pattern.compile("(? s;\n" - + "Encode a string using quoted-printable encoding.\n\n" - + "On encoding, when istext is set, newlines are not encoded, and white\n" - + "space at end of lines is. When istext is not set, \r and \n (CR/LF) are\n" - + "both encoded. When quotetabs is set, space and tabs are encoded."); + final public static PyString __doc__b2a_qp = + new PyString("b2a_qp(data, quotetabs=0, istext=1, header=0) -> s;\n" + + "Encode a string using quoted-printable encoding.\n\n" + + "On encoding, when istext is set, newlines are not encoded, and white\n" + + "space at end of lines is. When istext is not set, \r and \n (CR/LF) are\n" + + "both encoded. When quotetabs is set, space and tabs are encoded."); public static PyString b2a_qp(PyObject[] arg, String[] kws) { - ArgParser ap = new ArgParser("b2a_qp", arg, kws, new String[] {"s", "quotetabs", "istext", "header"}); + ArgParser ap = new ArgParser("b2a_qp", arg, kws, + new String[] {"s", "quotetabs", "istext", "header"}); boolean quotetabs = getIntFlagAsBool(ap, 1, 0, "an integer is required"); boolean istext = getIntFlagAsBool(ap, 2, 1, "an integer is required"); boolean header = getIntFlagAsBool(ap, 3, 0, "an integer is required"); - PyObject pyObject = ap.getPyObject(0); - BufferProtocol bp; - if (pyObject instanceof BufferProtocol) { - bp = (BufferProtocol) pyObject; - } else { - throw Py.TypeError("expected something conforming to the buffer protocol, got " - + pyObject.getType().fastGetName()); - } + PyObject data = ap.getPyObject(0); - PyBuffer bin_data = bp.getBuffer(PyBUF.SIMPLE); - int datalen = bin_data.getLen(); - StringBuilder sb = new StringBuilder(datalen); - try { + try (PyBuffer dataBuf = getByteBuffer(data)) { + int dataLen = dataBuf.getLen(); + StringBuilder sb = new StringBuilder(dataLen); String lineEnd = "\n"; + // Work out if line endings should be crlf. - for (int i = 0, m = bin_data.getLen(); i < m; i++) { - if ('\n' == bin_data.intAt(i)) { - if (i > 0 && '\r' == bin_data.intAt(i-1)) { + for (int i = 0, m = dataBuf.getLen(); i < m; i++) { + if ('\n' == dataBuf.intAt(i)) { + if (i > 0 && '\r' == dataBuf.intAt(i - 1)) { lineEnd = "\r\n"; } break; @@ -1072,21 +977,17 @@ public static PyString b2a_qp(PyObject[] arg, String[] kws) { int MAXLINESIZE = 76; int in = 0; - while (in < datalen) { - char ch = (char) bin_data.intAt(in); - if ((ch > 126) || - (ch == '=') || - (header && ch == '_') || - ((ch == '.') && (count == 0) && - ((in+1 == datalen) || (char) bin_data.intAt(in+1) == '\n' || (char) bin_data.intAt(in+1) == '\r')) || - (!istext && ((ch == '\r') || (ch == '\n'))) || - ((ch == '\t' || ch == ' ') && (in + 1 == datalen)) || - ((ch < 33) && - (ch != '\r') && (ch != '\n') && - (quotetabs || - (!quotetabs && ((ch != '\t') && (ch != ' ')))))) - { - if ((count + 3 )>= MAXLINESIZE) { + while (in < dataLen) { + char ch = (char) dataBuf.intAt(in); + if ((ch > 126) || (ch == '=') || (header && ch == '_') + || ((ch == '.') && (count == 0) + && ((in + 1 == dataLen) || (char) dataBuf.intAt(in + 1) == '\n' + || (char) dataBuf.intAt(in + 1) == '\r')) + || (!istext && ((ch == '\r') || (ch == '\n'))) + || ((ch == '\t' || ch == ' ') && (in + 1 == dataLen)) + || ((ch < 33) && (ch != '\r') && (ch != '\n') + && (quotetabs || (!quotetabs && ((ch != '\t') && (ch != ' ')))))) { + if ((count + 3) >= MAXLINESIZE) { sb.append('='); sb.append(lineEnd); count = 0; @@ -1094,69 +995,88 @@ public static PyString b2a_qp(PyObject[] arg, String[] kws) { qpEscape(sb, ch); in++; count += 3; - } - else { - if (istext && - ((ch == '\n') || - ((in+1 < datalen) && (ch == '\r') && - (bin_data.intAt(in+1) == '\n')))) - { + } else { + if (istext && ((ch == '\n') || ((in + 1 < dataLen) && (ch == '\r') + && (dataBuf.intAt(in + 1) == '\n')))) { count = 0; - /* Protect against whitespace on end of line */ + // Protect against whitespace on end of line int out = sb.length(); - if (out > 0 && ((sb.charAt(out-1) == ' ') || (sb.charAt(out-1) == '\t'))) { - ch = sb.charAt(out-1); - sb.setLength(out-1); - qpEscape(sb, ch); - } + if (out > 0 + && ((sb.charAt(out - 1) == ' ') || (sb.charAt(out - 1) == '\t'))) { + ch = sb.charAt(out - 1); + sb.setLength(out - 1); + qpEscape(sb, ch); + } - sb.append(lineEnd); - if (ch == '\r') { - in+=2; - } else { - in++; - } - } - else { - if ((in + 1 != datalen) && - ((char) bin_data.intAt(in+1) != '\n') && - (count + 1) >= MAXLINESIZE) { + sb.append(lineEnd); + if (ch == '\r') { + in += 2; + } else { + in++; + } + } else { + if ((in + 1 != dataLen) && ((char) dataBuf.intAt(in + 1) != '\n') + && (count + 1) >= MAXLINESIZE) { sb.append('='); sb.append(lineEnd); count = 0; - } + } count++; if (header && ch == ' ') { sb.append('_'); in++; - } - else { + } else { sb.append(ch); in++; } } } } - } finally { - bin_data.release(); + + return new PyString(sb.toString()); + + } catch (ClassCastException e) { + throw argMustBeBytes("b2a_qp", data); } - return new PyString(sb.toString()); } - -/* - public static void main(String[] args) { - String l = b2a_uu("Hello"); - System.out.println(l); - System.out.println(a2b_uu(l)); - - l = b2a_base64("Hello"); - System.out.println(l); - System.out.println(a2b_base64(l)); - - l = b2a_hqx("Hello-"); - System.out.println(l); - System.out.println(a2b_hqx(l)); + + /** + * We use this when the argument given to a conversion method is to be interpreted as text. If + * it is byte-like, the bytes are used unchanged, assumed in the "intended" character set. It + * may be a {@code PyUnicode}, in which case the it will be decoded to bytes using the default + * encoding ({@code sys.getdefaultencoding()}. + * + * @param text an object with the buffer protocol (or {@code unicode}) + * @return a byte-buffer view of argument (or default decoding if {@code unicode}) + * @throws ClassCastException where the text object does not implement the buffer protocol + */ + private static PyBuffer getByteBuffer(PyObject text) throws ClassCastException { + if (text instanceof PyUnicode) { + String s = ((PyUnicode) text).encode(); + return new SimpleStringBuffer(PyBUF.SIMPLE, null, s); + } else { + return ((BufferProtocol) text).getBuffer(PyBUF.SIMPLE); + } } -*/ + + /** + * Convenience method providing the exception when an argument is not the expected type, in the + * format "f() argument 1 must bytes or unicode, not type(arg)." + * + * @param f name of function of error (or could be any text) + * @param arg argument provided from which actual type will be reported + * @return TypeError to throw + */ + private static PyException argMustBeBytes(String f, PyObject arg) { + String fmt = "%s() argument 1 must bytes or unicode, not %s"; + String type = "null"; + if (arg instanceof PyObject) { + type = ((PyObject) arg).getType().fastGetName(); + } else if (arg != null) { + type = arg.getClass().getName(); + } + return Py.TypeError(String.format(fmt, f, type)); + } + } diff --git a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java index d06843e97..0b7044eae 100644 --- a/src/org/python/modules/bz2/PyBZ2CompressorDerived.java +++ b/src/org/python/modules/bz2/PyBZ2CompressorDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java index e60e81f20..03b7933f6 100644 --- a/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java +++ b/src/org/python/modules/bz2/PyBZ2DecompressorDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/bz2/PyBZ2FileDerived.java b/src/org/python/modules/bz2/PyBZ2FileDerived.java index 1586b1be7..05df6c1ec 100644 --- a/src/org/python/modules/bz2/PyBZ2FileDerived.java +++ b/src/org/python/modules/bz2/PyBZ2FileDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/cPickle.java b/src/org/python/modules/cPickle.java index 818373a84..77f85309f 100644 --- a/src/org/python/modules/cPickle.java +++ b/src/org/python/modules/cPickle.java @@ -1,3 +1,4 @@ +// Copyright (c)2019 Jython Developers /* * Copyright 1998 Finn Bock. * @@ -5,6 +6,7 @@ * Copyright (c) 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, * The Netherlands. */ +// Licensed to the PSF under a Contributor Agreement /* note about impl: instanceof vs. CPython type(.) is . @@ -289,10 +291,8 @@ *

    * Apart from the Pickler and Unpickler classes, the * module defines the following functions, and an exception: - * - *

    - *

    dump (object, file[, - * bin]) + *
    + *
    dump (object, file[, bin])
    *
    * Write a pickled representation of obect to the open file object * file. This is equivalent to @@ -300,41 +300,35 @@ * If the optional bin argument is present and nonzero, the binary * pickle format is used; if it is zero or absent, the (less efficient) * text pickle format is used. - *
    + * * - *

    - *

    load (file) + *
    load (file)
    *
    * Read a pickled object from the open file object file. This is * equivalent to "Unpickler(file).load()". - *
    + * * - *

    - *

    dumps (object[, - * bin]) + *
    dumps (object[, bin])
    *
    * Return the pickled representation of the object as a string, instead * of writing it to a file. If the optional bin argument is * present and nonzero, the binary pickle format is used; if it is zero * or absent, the (less efficient) text pickle format is used. - *
    + * * - *

    - *

    loads (string) + *
    loads (string)
    *
    * Read a pickled object from a string instead of a file. Characters in * the string past the pickled object's representation are ignored. - *
    + * * - *

    - *

    PicklingError + *
    PicklingError
    *
    * This exception is raised when an unpicklable object is passed to * Pickler.dump(). + *
    *
    * - * - *

    * For the complete documentation on the pickle module, please see the * "Python Library Reference" *


    @@ -781,10 +775,11 @@ private void save(PyObject object, boolean pers_save) { PyType t = object.getType(); if (t == TupleType && object.__len__() == 0) { - if (protocol > 0) + if (protocol > 0) { save_empty_tuple(object); - else + } else { save_tuple(object); + } return; } @@ -794,8 +789,9 @@ private void save(PyObject object, boolean pers_save) { return; } - if (save_type(object, t)) + if (save_type(object, t)) { return; + } if (!pers_save && inst_persistent_id != null && save_pers(object, inst_persistent_id)) { return; @@ -814,8 +810,9 @@ private void save(PyObject object, boolean pers_save) { tup = reduce.__call__(Py.newInteger(protocol)); } else { reduce = object.__findattr__("__reduce__"); - if (reduce == null) + if (reduce == null) { throw new PyException(UnpickleableError, object); + } tup = reduce.__call__(); } } else { @@ -883,9 +880,10 @@ final private void save_reduce(PyObject callable, PyObject arg_tup, if(protocol >= 2 && callableName != null && "__newobj__".equals(callableName.toString())) { PyObject cls = arg_tup.__finditem__(0); - if(cls.__findattr__("__new__") == null) + if(cls.__findattr__("__new__") == null) { throw new PyException(PicklingError, "args[0] from __newobj__ args has no __new__"); + } // TODO: check class save(cls); save(arg_tup.__getslice__(Py.One, Py.None)); @@ -915,40 +913,41 @@ final private void save_reduce(PyObject callable, PyObject arg_tup, final private boolean save_type(PyObject object, PyType type) { //System.out.println("save_type " + object + " " + cls); - if (type == NoneType) + if (type == NoneType) { save_none(object); - else if (type == StringType) + } else if (type == StringType) { save_string(object); - else if (type == UnicodeType) + } else if (type == UnicodeType) { save_unicode(object); - else if (type == IntType) + } else if (type == IntType) { save_int(object); - else if (type == LongType) + } else if (type == LongType) { save_long(object); - else if (type == FloatType) + } else if (type == FloatType) { save_float(object); - else if (type == TupleType) + } else if (type == TupleType) { save_tuple(object); - else if (type == ListType) + } else if (type == ListType) { save_list(object); - else if (type == DictionaryType || type == StringMapType) + } else if (type == DictionaryType || type == StringMapType) { save_dict(object); - else if (type == InstanceType) + } else if (type == InstanceType) { save_inst((PyInstance)object); - else if (type == ClassType) + } else if (type == ClassType) { save_global(object); - else if (type == TypeType) + } else if (type == TypeType) { save_global(object); - else if (type == FunctionType) + } else if (type == FunctionType) { save_global(object); - else if (type == BuiltinCallableType) + } else if (type == BuiltinCallableType) { save_global(object); - else if (type == ReflectedFunctionType) + } else if (type == ReflectedFunctionType) { save_global(object); - else if (type == BoolType) + } else if (type == BoolType) { save_bool(object); - else + } else { return false; + } return true; } @@ -1113,12 +1112,14 @@ private void save_tuple(PyObject object) { int len = object.__len__(); if (len > 0 && len <= 3 && protocol >= 2) { - for (int i = 0; i < len; i++) + for (int i = 0; i < len; i++) { save(object.__finditem__(i)); + } int m = getMemoPosition(d, object); if (m >= 0) { - for (int i = 0; i < len; i++) + for (int i = 0; i < len; i++) { file.write(POP); + } get(m); } else { @@ -1131,8 +1132,9 @@ private void save_tuple(PyObject object) { file.write(MARK); - for (int i = 0; i < len; i++) + for (int i = 0; i < len; i++) { save(object.__finditem__(i)); + } if (len > 0) { int m = getMemoPosition(d, object); @@ -1142,8 +1144,9 @@ private void save_tuple(PyObject object) { get(m); return; } - for (int i = 0; i < len+1; i++) + for (int i = 0; i < len+1; i++) { file.write(POP); + } get(m); return; } @@ -1158,9 +1161,9 @@ final private void save_empty_tuple(PyObject object) { } private void save_list(PyObject object) { - if (protocol > 0) + if (protocol > 0) { file.write(EMPTY_LIST); - else { + } else { file.write(MARK); file.write(LIST); } @@ -1188,15 +1191,16 @@ private void batch_appends(PyObject object) { } } } - if (countInBatch > 0) + if (countInBatch > 0) { file.write(APPENDS); + } } private void save_dict(PyObject object) { - if (protocol > 0) + if (protocol > 0) { file.write(EMPTY_DICT); - else { + } else { file.write(MARK); file.write(DICT); } @@ -1264,13 +1268,15 @@ final private void save_inst(PyInstance object) { } file.write(MARK); - if (protocol > 0) + if (protocol > 0) { save(cls); + } if (args != null) { int len = args.__len__(); - for (int i = 0; i < len; i++) + for (int i = 0; i < len; i++) { save(args.__finditem__(i)); + } } int mid = putMemo(get_id(object), object); @@ -1305,12 +1311,14 @@ final private void save_global(PyObject object) { final private void save_global(PyObject object, PyObject name) { - if (name == null) + if (name == null) { name = object.__findattr__("__name__"); + } PyObject module = object.__findattr__("__module__"); - if (module == null || module == Py.None) + if (module == null || module == Py.None) { module = whichmodule(object, name); + } if(protocol >= 2) { PyTuple extKey = new PyTuple(module, name); @@ -1380,8 +1388,9 @@ final private static PyObject whichmodule(PyObject cls, PyObject clsname) { PyObject name = classmap.get(cls); - if (name != null) + if (name != null) { return name; + } name = new PyString("__main__"); @@ -1465,21 +1474,27 @@ private int findIndex(int key, Object value) { if (tkey == key && value == values[index]) { return index; } - if (values[index] == null) return -1; + if (values[index] == null) { + return -1; + } index = (index+stepsize) % maxindex; } } public int findPosition(int key, Object value) { int idx = findIndex(key, value); - if (idx < 0) return -1; + if (idx < 0) { + return -1; + } return position[idx]; } public Object findValue(int key, Object value) { int idx = findIndex(key, value); - if (idx < 0) return null; + if (idx < 0) { + return null; + } return values[idx]; } @@ -1514,7 +1529,9 @@ private final void insertkey(int key, int pos, Object value) { private final void resize(int capacity) { int p = prime; for(; p= capacity) break; + if (primes[p] >= capacity) { + break; + } } if (primes[p] < capacity) { throw Py.ValueError("can't make hashtable of size: " + @@ -1538,14 +1555,18 @@ private final void resize(int capacity) { for(int i=0; i keys.length) resize(keys.length+1); + if (2*filled > keys.length) { + resize(keys.length+1); + } insertkey(key, pos, value); } } @@ -1603,8 +1624,9 @@ public PyObject load() { // System.out.println("load:" + s); // for (int i = 0; i < stackTop; i++) // System.out.println(" " + stack[i]); - if (s.length() < 1) + if (s.length() < 1) { load_eof(); + } char key = s.charAt(0); switch (key) { case PERSID: load_persid(); break; @@ -1670,9 +1692,11 @@ public PyObject load() { final private int marker() { - for (int k = stackTop-1; k >= 0; k--) - if (stack[k] == mark) + for (int k = stackTop-1; k >= 0; k--) { + if (stack[k] == mark) { return stackTop-k-1; + } + } throw new PyException(UnpicklingError, "Inputstream corrupt, marker not found"); } @@ -1684,8 +1708,9 @@ final private void load_eof() { private void load_proto() { int proto = file.read(1).charAt(0); - if (proto < 0 || proto > 2) + if (proto < 0 || proto > 2) { throw Py.ValueError("unsupported pickle protocol: " + proto); + } } @@ -1807,12 +1832,13 @@ private void load_bin_long(int length) { } private int read_binint(int length) { - if (length == 1) + if (length == 1) { return file.read(1).charAt(0); - else if (length == 2) + } else if (length == 2) { return read_binint2(); - else + } else { return read_binint(); + } } final private void load_float() { @@ -1838,8 +1864,9 @@ final private void load_string() { String value; char quote = line.charAt(0); - if (quote != '"' && quote != '\'') + if (quote != '"' && quote != '\'') { throw Py.ValueError("insecure string pickle"); + } int nslash = 0; int i; @@ -1847,19 +1874,23 @@ final private void load_string() { int n = line.length(); for (i = 1; i < n; i++) { ch = line.charAt(i); - if (ch == quote && nslash % 2 == 0) + if (ch == quote && nslash % 2 == 0) { break; - if (ch == '\\') + } + if (ch == '\\') { nslash++; - else + } else { nslash = 0; + } } - if (ch != quote) + if (ch != quote) { throw Py.ValueError("insecure string pickle"); + } for (i++ ; i < line.length(); i++) { - if (line.charAt(i) > ' ') + if (line.charAt(i) > ' ') { throw Py.ValueError("insecure string pickle " + i); + } } value = PyString.decode_UnicodeEscape(line, 1, n-1, "strict", false); @@ -1988,9 +2019,10 @@ final private void load_global() { final private PyObject find_class(String module, String name) { if (find_global != null) { - if (find_global == Py.None) - throw new PyException(UnpicklingError, + if (find_global == Py.None) { + throw new PyException(UnpicklingError, "Global and instance pickles are not supported."); + } return find_global.__call__(new PyString(module), new PyString(name)); } @@ -2049,8 +2081,9 @@ final private PyObject[] make_array(PyObject seq) { int n = seq.__len__(); PyObject[] objs= new PyObject[n]; - for(int i=0; i 0) { lines.append(line); total += line.__len__(); - if (0 < sizehint_int && sizehint_int <= total) + if (0 < sizehint_int && sizehint_int <= total) { break; + } line = readline(); } return lines; } + public static final String __doc__truncate = + "truncate(): truncate the file at the current position."; /** * truncate the file at the current position. */ @@ -329,12 +371,16 @@ public synchronized void truncate(long pos) { throw Py.IOError("Negative size not allowed"); } int pos_int = _convert_to_int(pos); - if (pos_int < 0) + if (pos_int < 0) { pos_int = this.pos; + } buf.setLength(pos_int); this.pos = pos_int; } + public static final String __doc__write = + "write(s) -- Write a string to the file" + + "\n\nNote (hack:) writing None resets the buffer"; /** * Write a string to the file. * @param obj The data to write. @@ -361,8 +407,9 @@ public synchronized void write(String s) { int l = spos - slen; char[] bytes = new char[l]; - for (int i = 0; i < l - 1; i++) + for (int i = 0; i < l - 1; i++) { bytes[i] = '\0'; + } buf.append(bytes); slen = spos; @@ -393,12 +440,17 @@ public synchronized void write(String s) { */ public synchronized void writeChar(char ch) { int len = buf.length(); - if (len <= pos) + if (len <= pos) { buf.setLength(pos + 1); + } buf.setCharAt(pos++, ch); } - + public static final String __doc__writelines = + "writelines(sequence_of_strings) -> None. Write the strings to the file.\n" + + "\n" + + "Note that newlines are not added. The sequence can be any iterable object\n" + + "producing strings. This is equivalent to calling write() for each string."; /** * Write a list of strings to the file. */ @@ -408,7 +460,7 @@ public void writelines(PyObject lines) { } } - + public static final String __doc__flush = "flush(): does nothing."; /** * Flush the internal buffer. Does nothing. */ @@ -416,7 +468,11 @@ public void flush() { _complain_ifclosed(); } - + public static final String __doc__getvalue = + "getvalue([use_pos]) -- Get the string value." + + "\n" + + "If use_pos is specified and is a true value, then the string returned\n" + + "will include only the text up to the current file position.\n"; /** * Retrieve the entire contents of the ``file'' at any time * before the StringIO object's close() method is called. @@ -429,6 +485,7 @@ public synchronized PyString getvalue() { } + private static String[] strings = new String[256]; static String getString(char ch) { if (ch > 255) { @@ -443,5 +500,5 @@ static String getString(char ch) { } return s; } - } + diff --git a/src/org/python/modules/cmath.java b/src/org/python/modules/cmath.java index 0c84b9915..cc5df1336 100644 --- a/src/org/python/modules/cmath.java +++ b/src/org/python/modules/cmath.java @@ -475,9 +475,8 @@ public static PyComplex cosh(PyObject z) { * Helper to compute either cos z or cosh z. * * @param z - * @param h true to compute cosh z, false to compute cos - * z. - * @return + * @param h true for cosh, false for cos. + * @return cos z or cosh z */ private static PyComplex cosOrCosh(PyComplex z, boolean h) { double x, y, u, v; @@ -631,7 +630,7 @@ public static PyTuple polar(PyObject in) { * * @param r radius * @param phi angle - * @return + * @return re */ public static PyComplex rect(double r, double phi) { double x, y; @@ -828,9 +827,8 @@ public static PyComplex sinh(PyObject z) { * Helper to compute either sin z or sinh z. * * @param z - * @param h true to compute sinh z, false to compute sin - * z. - * @return + * @param h true for sinh, false for sin. + * @return sinh z or sin z. */ private static PyComplex sinOrSinh(PyComplex z, boolean h) { double x, y, u, v; @@ -1133,7 +1131,7 @@ private static PyComplex tanOrTanh(PyComplex z, boolean h) { * @param arg to include in check * @return result if arg was NaN or result was not * NaN - * @throws PyException (ValueError) if result was NaN and + * @throws PyException {@code ValueError} if result was NaN and * arg was not NaN */ private static PyComplex exceptNaN(PyComplex result, PyComplex arg) throws PyException { diff --git a/src/org/python/modules/gc.java b/src/org/python/modules/gc.java index 997a97a6d..8f6f31a3c 100644 --- a/src/org/python/modules/gc.java +++ b/src/org/python/modules/gc.java @@ -15,6 +15,7 @@ import org.python.core.JyAttribute; import org.python.core.Py; +import org.python.core.PyException; import org.python.core.PyList; import org.python.core.PyObject; import org.python.core.PyInstance; @@ -27,148 +28,129 @@ import org.python.modules._weakref.GlobalRef; import org.python.modules._weakref.ReferenceBackend; -//These imports belong to the out-commented section on MXBean-based -//gc-sync far below. That section is kept to document this failed +//These imports belong to the out commented section on MXBean-based +//gc sync far below. That section is kept to document this failed //approach and allow easy reproduction of this failure. //import java.lang.management.*; //import javax.management.*; //import javax.management.openmbean.*; /** + * In Jython, the gc module notably differs from that in CPython. This comes from the different ways + * Jython and CPython perform garbage collection. While CPython's garbage collection is based on + * reference + * counting, Jython is backed by Java's gc, which is based on a + * mark-and-sweep + * approach. *

    - * In Jython, the gc-module notably differs from that in CPython. - * This comes from the different ways Jython and CPython perform - * garbage-collection. While CPython's garbage collection is based on - * - * reference-counting, Jython is backed by Java's gc, which is - * based on a - * - * mark-and-sweep-approach. - *

    + * This difference becomes most notable if finalizers are involved that perform resurrection. While + * the resurrected object itself behaves rather similar between Jython and CPython, things are more + * delicate with objects that are reachable (i.e. strongly referenced) via the resurrected object + * exclusively. While in CPython such objects do not get their finalizers called, Jython/Java would + * call all their finalizers. That is because Java detects the whole unreachable subgraph as garbage + * and thus calls all their finalizers without any chance of direct intervention. CPython instead + * detects the unreachable object and calls its finalizer, which makes the object reachable again. + * Then all other objects are reachable from it and CPython does not treat them as garbage and does + * not call their finalizers at all. This further means that in Jython weak references to such + * indirectly resurrected objects break, while these persist in CPython. *

    - * This difference becomes most notable if finalizers are involved that perform resurrection. - * While the resurrected object itself behaves rather similar between Jython and CPython, - * things are more delicate with objects that are reachable (i.e. strongly referenced) - * via the resurrected object exclusively. - * While in CPython such objects do not get their finalizers called, Jython/Java would - * call all their finalizers. That is because Java detects the whole unreachable subgraph - * as garbage and thus calls all their finalizers without any chance of direct intervention. - * CPython instead detects the unreachable object and calls its finalizer, which makes the - * object reachable again. Then all other objects are reachable from it and CPython does not - * treat them as garbage and does not call their finalizers at all. - * This further means that in Jython weak references to such indirectly resurrected objects - * break, while these persist in CPython. - *

    + * As of Jython 2.7, the gc module offers some options to emulate CPython behavior. Especially see + * the flags {@link #PRESERVE_WEAKREFS_ON_RESURRECTION}, {@link #DONT_FINALIZE_RESURRECTED_OBJECTS} + * and {@link #DONT_FINALIZE_CYCLIC_GARBAGE} for this. *

    - * As of Jython 2.7, the gc-module offers some options to emulate CPython-behavior. - * Especially see the flags {@link #PRESERVE_WEAKREFS_ON_RESURRECTION}, - * {@link #DONT_FINALIZE_RESURRECTED_OBJECTS} and {@link #DONT_FINALIZE_CYCLIC_GARBAGE} - * for this. - *

    + * Another difference is that CPython's gc module offers some debug features like counting of + * collected cyclic trash, which are hard to support by Jython. As of Jython 2.7 the introduction of + * a traverseproc mechanism (c.f. {@link org.python.core.Traverseproc}) made support of these + * features feasible. As support of these features comes with a significant emulation cost, one must + * explicitly tell gc to perform this. To make objects subject to cyclic trash counting, these + * objects must be gc-monitored in Jython. See {@link #monitorObject(PyObject)}, + * {@link #unmonitorObject(PyObject)}, {@link #MONITOR_GLOBAL} and {@link #stopMonitoring()} for + * this. *

    - * Another difference is that CPython's gc-module offers some debug-features like counting - * of collected cyclic trash, which are hard to support by Jython. As of Jython 2.7 the - * introduction of a traverseproc-mechanism (c.f. {@link org.python.core.Traverseproc}) - * made support of these features feasible. As support of these features comes - * with a significant emulation-cost, one must explicitly tell gc to perform this. - * To make objects subject to cyclic trash-counting, these objects must be gc-monitored in - * Jython. See {@link #monitorObject(PyObject)}, {@link #unmonitorObject(PyObject)}, - * {@link #MONITOR_GLOBAL} and {@link #stopMonitoring()} for this.
    - * If at least one object is gc-monitored, {@link #collect()} works synchronously in the - * sense that it blocks until all gc-monitored objects that are garbage actually have been - * collected and had their finalizers called and completed. {@link #collect()} will report - * the number of collected objects in the same manner as in CPython, i.e. counts only those - * that participate in reference cycles. This allows a unified test-implementation across - * Jython and CPython (which applies to most tests in test_gc.py). If not any object is - * gc-monitored, {@link #collect()} just delegates to {@link java.lang.System.gc()}, runs - * asynchronously (i.e. non-blocking) and returns {@link #UNKNOWN_COUNT}. - * See also {@link #DEBUG_SAVEALL} for a useful gc-debugging feature that is supported by - * Jython from version 2.7 onwards. - *

    + * If at least one object is gc-monitored, {@link #collect()} works synchronously in the sense that + * it blocks until all gc-monitored objects that are garbage actually have been collected and had + * their finalizers called and completed. {@link #collect()} will report the number of collected + * objects in the same manner as in CPython, i.e. counts only those that participate in reference + * cycles. This allows a unified test implementation across Jython and CPython (which applies to + * most tests in test_gc.py). If not any object is gc-monitored, {@link #collect()} just delegates + * to {@link java.lang.System#gc()}, runs asynchronously (i.e. non-blocking) and returns + * {@link #UNKNOWN_COUNT}. See also {@link #DEBUG_SAVEALL} for a useful gc debugging feature that is + * supported by Jython from version 2.7 onwards. *

    - * Implementing all these features in Jython involved a lot of synchronization logic. - * While care was taken to implement this without using timeouts as far as possible and - * rely on locks, states and system/hardware independent synchronization techniques, - * this was not entirely feasible.
    - * The aspects that were only feasible using a timeout are waiting for gc to enqueue all - * collected objects (i.e. weak references to monitored objects that were gc'ed) to the - * reference queue and waiting for gc to run all PyObject-finalizers. - *

    + * Implementing all these features in Jython involved a lot of synchronization logic. While care was + * taken to implement this without using timeouts as far as possible and rely on locks, states and + * system/hardware independent synchronization techniques, this was not entirely feasible.
    + * The aspects that were only feasible using a timeout are waiting for gc to enqueue all collected + * objects (i.e. weak references to monitored objects that were gc'ed) to the reference queue and + * waiting for gc to run all PyObject finalizers. *

    * Waiting for trash could in theory be strictly synchronized by using {@code MXBean}s, i.e. - * GarbageCollectionNotificationInfo and related API. - * However, experiments showed that the arising gc-notifications do not reliably indicate - * when enqueuing was done for a specific gc-run. We kept the experimental implementation - * in source-code comments to allow easy reproducibility of this issue. (Note that out-commented - * code contradicts Jython-styleguide, but this one - however - is needed to document this - * infeasible approach and is explicitly declared accordingly).
    - * But how is sync done now? - * We insert a sentinel before running gc and wait until this sentinel was collected. - * Timestamps are taken to give us an idea at which time-scales the gc of the current JVM - * performs. We then wait until twice the measured time (i.e. duration from call to - * {@link java.lang.System#gc()} until the sentinel reference was enqueued) has passed after - * the last reference was enqueued by gc. While this approach is not entirely safe in theory, - * it passes all tests on various systems and machines we had available for testing so far. - * We consider it more robust than a fixed-length timeout and regard it the best known feasible - * compromise to emulate synchronous gc-runs in Java. - *

    + * GarbageCollectionNotificationInfo and related API. However, experiments + * showed that the arising gc notifications do not reliably indicate when enqueuing was done for a + * specific gc run. We kept the experimental implementation in source code comments to allow easy + * reproducibility of this issue. (Note that out commented code contradicts Jython styleguide, but + * this one - however - is needed to document this infeasible approach and is explicitly declared + * accordingly). + *

    + * But how is sync done now? We insert a sentinel before running gc and wait until this + * sentinel was collected. Timestamps are taken to give us an idea at which time scales the gc of + * the current JVM performs. We then wait until twice the measured time (i.e. duration from call to + * {@link java.lang.System#gc()} until the sentinel reference was enqueued) has passed after the + * last reference was enqueued by gc. While this approach is not entirely safe in theory, it passes + * all tests on various systems and machines we had available for testing so far. We consider it + * more robust than a fixed-length timeout and regard it the best known feasible compromise to + * emulate synchronous gc runs in Java. *

    * The other timing-based synchronization issue - waiting for finalizers to run - is solved as - * follows. Since PyObject-finalizers are based on - * {@link org.python.core.finalization.FinalizeTrigger}s, Jython has full control about - * these finalization process from a central point. Before such a finalizer runs, it calls - * {@link #notifyPreFinalization()} and when it is done, it calls - * {@link #notifyPostFinalization()}. While processing of a finalizer can be of arbitrary - * duration, it widely holds that Java's gc-thread calls the next finalizer almost - * instantaneously after the former. That means that a timestamp taken in - * {@link #notifyPreFinalization()} is usually delayed only few milliseconds - * - often even reported as 0 milliseconds - after the last taken timestamp in - * {@link #notifyPostFinalization()} (i.e. that was called by the previous finalizer). - * Jython's gc-module assumes the end of Java's finalization process if - * {@link #postFinalizationTimeOut} milliseconds passed after a call of - * {@link #notifyPostFinalization()} without another call to + * follows. Since PyObject finalizers are based on + * {@link org.python.core.finalization.FinalizeTrigger}s, Jython has full control about these + * finalization process from a central point. Before such a finalizer runs, it calls + * {@link #notifyPreFinalization()} and when it is done, it calls {@link #notifyPostFinalization()}. + * While processing of a finalizer can be of arbitrary duration, it widely holds that Java's gc + * thread calls the next finalizer almost instantaneously after the former. That means that a + * timestamp taken in {@link #notifyPreFinalization()} is usually delayed only few milliseconds - + * often even reported as 0 milliseconds - after the last taken timestamp in + * {@link #notifyPostFinalization()} (i.e. that was called by the previous finalizer). Jython's gc + * module assumes the end of Java's finalization process if {@link #postFinalizationTimeOut} + * milliseconds passed after a call of {@link #notifyPostFinalization()} without another call to * {@link #notifyPreFinalization()} in that time. The default value of - * {@link #postFinalizationTimeOut} is {@code 100}, which is far larger than the - * usual almost-zero duration between finalizer calls.
    - * This process can be disturbed by third-party finalizers of non-PyObjects brought - * into the process by external libraries. If these finalizers are of short duration - * (which applies to typical finalizers), one can deal with this by adjusting - * {@link #postFinalizationTimeOut}, which was declared {@code public} for exactly this - * purpose. However if the external framework causing the issue is Jython-aware, a - * cleaner solution would be to let its finalizers call {@link #notifyPreFinalization()} - * and {@link #notifyPostFinalization()} appropriately. In that case these finalizers - * must not terminate by throwing an exception before {@link #notifyPostFinalization()} - * was called. This is a strict requirement, since a deadlock can be caused otherwise.
    - *
    - * Note that the management API - * (c.f. - * com.sun.management.GarbageCollectionNotificationInfo) does not emit any - * notifications that allow to detect the end of the finalization-phase. So this API - * provides no alternative to the described technique. - *

    + * notifications that allow to detect the end of the finalization phase. So this API provides no + * alternative to the described technique. *

    - * Usually Java's gc provides hardly any guarantee about its collection- and finalization- - * process. It not even guarantees that finalizers are called at all (c.f. - * http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java). - * While at least the most common JVM implementations usually do call finalizers - * reliably under normal conditions, there still is no specific finalization-order guaranteed - * (one might reasonably expect that this would be related to reference-connection graph - * topology, but this appears not to be the case). - * However Jython now offers some functionality to compensate this - * situation. Via {@link #registerPreFinalizationProcess(Runnable)} and - * {@link #registerPostFinalizationProcess(Runnable)} and related methods one can now - * listen to beginning and end of the finalization process. Note that this functionality - * relies on the technique described in the former paragraph (i.e. based on calls to - * {@link #notifyPreFinalization()} and {@link #notifyPostFinalization()}) and thus - * underlies its unsafety, if third-party finalizers are involved. Such finalizers can - * cause false-positive runs of registered (pre/post)-finalization-processes, so this - * feature should be used with some care. It is recommended to use it only in such a way - * that false-positive runs would not cause serious harm, but only some loss in - * performance or so. - *

    + * Usually Java's gc provides hardly any guarantee about its collection and finalization process. It + * not even guarantees that finalizers are called at all (c.f. + * http://howtodoinjava.com/2012/10/31/why-not-to-use-finalize-method-in-java). While + * at least the most common JVM implementations usually do call finalizers reliably under + * normal conditions, there still is no specific finalization order guaranteed (one might reasonably + * expect that this would be related to reference connection graph topology, but this appears not to + * be the case). However Jython now offers some functionality to compensate this situation. Via + * {@link #registerPreFinalizationProcess(Runnable)} and + * {@link #registerPostFinalizationProcess(Runnable)} and related methods one can now listen to + * beginning and end of the finalization process. Note that this functionality relies on the + * technique described in the former paragraph (i.e. based on calls to + * {@link #notifyPreFinalization()} and {@link #notifyPostFinalization()}) and thus underlies its + * unsafety, if third-party finalizers are involved. Such finalizers can cause false-positive runs + * of registered (pre/post) finalization processes, so this feature should be used with some care. + * It is recommended to use it only in such a way that false-positive runs would not cause serious + * harm, but only some loss in performance or so. */ public class gc { /** @@ -178,11 +160,11 @@ public class gc { * reserved to indicate an error. */ public static final int UNKNOWN_COUNT = -2; - - /* Jython-specific gc-flags: */ + + /* Jython-specific gc flags: */ /** * This flag tells every newly created PyObject to register for - * gc-monitoring. This allows {@link #collect()} to report the + * gc monitoring. This allows {@link #collect()} to report the * number of collected objects. * * @see #setJythonGCFlags(short) @@ -195,7 +177,7 @@ public class gc { /** * CPython prior to 3.4 does not finalize cyclic garbage * PyObjects, while Jython does this by default. This flag - * tells Jython's gc to mimic CPython <3.4 behavior (i.e. + * tells Jython's gc to mimic CPython <3.4 behavior (i.e. * add such objects to {@code gc.garbage} list instead). * * @see #setJythonGCFlags(short) @@ -238,7 +220,7 @@ public class gc { * and in unpredictable order). This flag emulates CPython * behavior in Jython. Note that this emulation comes with a * significant cost as it can delay collection of many objects - * for several gc-cycles. Its main intention is for debugging + * for several gc cycles. Its main intention is for debugging * resurrection-sensitive code. * * @see #setJythonGCFlags(short) @@ -253,31 +235,31 @@ public class gc { /** *

    - * Reflection-based traversion is an inefficient fallback-method to - * traverse PyObject-subtypes that don't implement + * Reflection-based traversal is an inefficient fallback method to + * traverse PyObject subtypes that don't implement * {@link org.python.core.Traverseproc} and * are not marked as {@link org.python.core.Untraversable}. * Such a situation indicates that the programmer was not aware of - * Jython's traverseproc-mechanism and reflection is used to + * Jython's traverseproc mechanism and reflection is used to * compensate this. *

    *

    - * This flag allows to inhibit reflection-based traversion. If it is + * This flag allows to inhibit reflection-based traversal. If it is * activated, objects that don't implement * {@link org.python.core.Traverseproc} * are always treated as if they were marked as * {@link org.python.core.Untraversable}. *

    *

    - * Note that reflection-based traversion fallback is performed by - * default. Further note that Jython emits warning-messages if - * reflection-based traversion occurs or if an object is encountered + * Note that reflection-based traversal fallback is performed by + * default. Further note that Jython emits warning messages if + * reflection-based traversal occurs or if an object is encountered * that neither implements {@link org.python.core.Traverseproc} * nor is marked as {@link org.python.core.Untraversable} (even if - * reflection-based traversion is inhibited). See + * reflection-based traversal is inhibited). See * {@link #SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING} and * {@link #INSTANCE_TRAVERSE_BY_REFLECTION_WARNING} to control - * these warning-messages. + * these warning messages. *

    * * @see #setJythonGCFlags(short) @@ -292,19 +274,19 @@ public class gc { /** *

    * If this flag is not set, gc warns whenever an object would be subject to - * reflection-based traversion. + * reflection-based traversal. * Note that if this flag is not set, the warning will occur even if - * reflection-based traversion is not active. The purpose of this behavior is - * to identify objects that don't properly support the traverseproc-mechanism, - * i.e. instances of PyObject-subclasses that neither implement + * reflection-based traversal is not active. The purpose of this behavior is + * to identify objects that don't properly support the traverseproc mechanism, + * i.e. instances of PyObject subclasses that neither implement * {@link org.python.core.Traverseproc}, - * nor are annotated with the {@link org.python.core.Untraversable}-annotation. + * nor are annotated with the {@link org.python.core.Untraversable} annotation. *

    *

    - * A SUPPRESS-flag was chosen rather than a WARN-flag, so that warning is the + * A SUPPRESS flag was chosen rather than a WARN flag, so that warning is the * default behavior - the user must actively set this flag in order to not to * be warned. - * This is because in an ideal implementation reflection-based traversion never + * This is because in an ideal implementation reflection-based traversal never * occurs; it is only an inefficient fallback. *

    * @@ -317,11 +299,11 @@ public class gc { public static final short SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING = (1<<7); /** - * Makes gc emit reflection-based traversion warning for every traversed + * Makes gc emit reflection-based traversal warning for every traversed * object instead of only once per class. - * A potential reflection-based traversion occurs whenever an object is + * A potential reflection-based traversal occurs whenever an object is * traversed that neither implements {@link org.python.core.Traverseproc}, - * nor is annotated with the {@link org.python.core.Untraversable}-annotation. + * nor is annotated with the {@link org.python.core.Untraversable} annotation. * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() @@ -333,12 +315,12 @@ public class gc { /** * In Jython one usually uses {@code Py.writeDebug} for debugging output. - * However that method is only verbose if an appropriate verbose-level - * was set. In CPython it is enough to set gc-{@code DEBUG} flags to get - * gc-messages, no matter what overall verbose level is selected. + * However that method is only verbose if an appropriate verbose level + * was set. In CPython it is enough to set gc {@code DEBUG} flags to get + * gc messages, no matter what overall verbose level is selected. * This flag tells Jython to use {@code Py.writeDebug} for debugging output. - * If it is not set (default-case), gc-debugging output (if gc-{@code VERBOSE} - * or -{@code DEBUG} flags are set) is directly written to {@code System.err}. + * If it is not set (default case), gc debugging output (if gc {@code VERBOSE} + * or {@code DEBUG} flags are set) is directly written to {@code System.err}. * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() @@ -348,8 +330,8 @@ public class gc { public static final short USE_PY_WRITE_DEBUG = (1<<9); /** - * Enables collection-related verbose-output. - * + * Enables collection-related verbose output. + * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() * @see #addJythonGCFlags(short) @@ -358,7 +340,7 @@ public class gc { public static final short VERBOSE_COLLECT = (1<<10); /** - * Enables weakref-related verbose-output. + * Enables weakref-related verbose output. * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() @@ -368,7 +350,7 @@ public class gc { public static final short VERBOSE_WEAKREF = (1<<11); /** - * Enables delayed finalization related verbose-output. + * Enables delayed finalization related verbose output. * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() @@ -378,7 +360,7 @@ public class gc { public static final short VERBOSE_DELAYED = (1<<12); /** - * Enables finalization-related verbose-output. + * Enables finalization-related verbose output. * * @see #setJythonGCFlags(short) * @see #getJythonGCFlags() @@ -388,7 +370,7 @@ public class gc { public static final short VERBOSE_FINALIZE = (1<<13); /** - * Bit-combination of the flags {@link #VERBOSE_COLLECT}, + * Bit combination of the flags {@link #VERBOSE_COLLECT}, * {@link #VERBOSE_WEAKREF}, {@link #VERBOSE_DELAYED}, * {@link #VERBOSE_FINALIZE}. * @@ -456,7 +438,7 @@ public class gc { public static final int DEBUG_SAVEALL = (1<<5); /** - * Bit-combination of the flags {@link #DEBUG_COLLECTABLE}, + * Bit combination of the flags {@link #DEBUG_COLLECTABLE}, * {@link #DEBUG_UNCOLLECTABLE}, {@link #DEBUG_INSTANCES}, * {@link #DEBUG_OBJECTS}, {@link #DEBUG_SAVEALL}. * @@ -469,12 +451,12 @@ public class gc { DEBUG_OBJECTS | DEBUG_SAVEALL; - private static short gcFlags = 0; + private static short gcFlags = DONT_TRAVERSE_BY_REFLECTION; private static int debugFlags = 0; private static boolean monitorNonTraversable = false; private static boolean waitingForFinalizers = false; - private static AtomicBoolean gcRunning = new AtomicBoolean(false); - private static HashSet monitoredObjects; + private static final AtomicBoolean gcRunning = new AtomicBoolean(false); + private static final Set monitoredObjects = new HashSet<>(); private static HashSet> reflectionWarnedClasses; private static ReferenceQueue gcTrash; private static int finalizeWaitCount = 0; @@ -489,8 +471,10 @@ public class gc { public static PyList garbage = new PyList(); /* Finalization preprocess/postprocess-related declarations: */ - private static List preFinalizationProcess, postFinalizationProcess; - private static List preFinalizationProcessRemove, postFinalizationProcessRemove; + private static final List preFinalizationProcess = new ArrayList<>(); + private static final List postFinalizationProcess = new ArrayList<>(); + private static final List preFinalizationProcessRemove = new ArrayList<>(); + private static final List postFinalizationProcessRemove = new ArrayList<>(); private static Thread postFinalizationProcessor; public static long postFinalizationTimeOut = 100; private static long postFinalizationTimestamp = System.currentTimeMillis()-2*postFinalizationTimeOut; @@ -700,27 +684,30 @@ public void initStr(PyObject referent) { } } + @Override public String toString() { return str; } + @Override public int hashCode() { return hashCode; } + @Override public boolean equals(Object ob) { Object ownReferent = get(); if (ob instanceof WeakReferenceGC) { Object otherReferent = ((WeakReferenceGC) ob).get(); if (ownReferent == null || otherReferent == null) { return ownReferent == otherReferent && - /* We compare the cached hash-codes in order to get an idea + /* We compare the cached hash codes in order to get an idea * whether in the both-null-case the referent was equal once. */ hashCode == ((WeakReferenceGC) ob).hashCode; } else { return otherReferent.equals(ownReferent) - /* Here the hash-codes are only compared as a consistency check. */ + /* Here the hash codes are only compared as a consistency check. */ && ((WeakReferenceGC) ob).hashCode == hashCode; } } else if (ob instanceof WeakrefGCCompareDummy) { @@ -728,13 +715,13 @@ public boolean equals(Object ob) { ((WeakrefGCCompareDummy) ob).compare == null) { return ownReferent == ((WeakrefGCCompareDummy) ob).compare && - /* We compare the cached hash-codes in order to get an idea + /* We compare the cached hash codes in order to get an idea * whether in the both-null-case the referent was equal once. */ hashCode == ((WeakrefGCCompareDummy) ob).hashCode; } else { return ownReferent.equals(((WeakrefGCCompareDummy) ob).compare) - /* Here the hash-codes are only compared as a consistency check. */ + /* Here the hash codes are only compared as a consistency check. */ && hashCode == ((WeakrefGCCompareDummy) ob).hashCode; } } else { @@ -748,7 +735,7 @@ private static class WeakrefGCCompareDummy { new WeakrefGCCompareDummy(); protected PyObject compare; int hashCode = 0; - + public void setCompare(PyObject compare) { this.compare = compare; hashCode = System.identityHashCode(compare); @@ -759,10 +746,12 @@ public void clearCompare() { hashCode = 0; } + @Override public int hashCode() { return hashCode; } - + + @Override @SuppressWarnings("rawtypes") public boolean equals(Object ob) { if (ob instanceof Reference) { @@ -777,11 +766,12 @@ public boolean equals(Object ob) { private static class GCSentinel { Thread waiting; - + public GCSentinel(Thread notifyOnFinalize) { waiting = notifyOnFinalize; } + @Override protected void finalize() throws Throwable { notifyPreFinalization(); if ((gcFlags & VERBOSE_COLLECT) != 0) { @@ -878,7 +868,7 @@ public static void restoreFinalizer(PyObject obj) { cm = (CycleMarkAttr) JyAttribute.getAttr(obj, JyAttribute.GC_CYCLE_MARK_ATTR); cyclic = cm != null && cm.isUncollectable(); } - + if ((gcFlags & VERBOSE_DELAYED) != 0 || (gcFlags & VERBOSE_FINALIZE) != 0) { writeDebug("gc", "notify finalizer abort; cyclic? "+cyclic); } @@ -891,9 +881,9 @@ public static void restoreFinalizer(PyObject obj) { * this does not prevent callbacks, unless it is called during * finalization phase (e.g. by a finalizer) and * {@link #delayedWeakrefCallbacksEnabled()} returns {@code true}. - * In a manual fashion, one can enforce this by using the gc-flag + * In a manual fashion, one can enforce this by using the gc flag * {@link #FORCE_DELAYED_WEAKREF_CALLBACKS}. Alternatively, one can - * use the automatic way via the gc-flag + * use the automatic way via the gc flag * {@link #PRESERVE_WEAKREFS_ON_RESURRECTION}, but then one would * not need to call this method anyway. The manual way has better * performance, but also brings more responsibilies. @@ -927,6 +917,7 @@ private static void performFinalization(PyObject del) { } } + @Override public void run() { if ((gcFlags & VERBOSE_DELAYED) != 0) { writeDebug("gc", "run delayed finalization. Index: "+ @@ -1038,7 +1029,7 @@ public void run() { } if (delayedFinalizationMode == MARK_REACHABLE_CRITICALS && !criticals.isEmpty() && !criticalReachables.isEmpty()) { - /* This means some critical-reachables might be not critical-reachable any more. + /* This means some critical reachables might be not critical-reachable any more. * In a synchronized gc collection approach System.gc should run again while * something like this is found. (Yes, not exactly a cheap task, but since this * is for debugging, correctness counts.) @@ -1098,6 +1089,7 @@ private static void updateDelayedFinalizationState() { // If delayed callbacks were turned off, we process remaining // queued callbacks immediately (but in a new thread though): Thread dlcProcess = new Thread() { + @Override public void run() { GlobalRef.processDelayedCallbacks(); } @@ -1113,16 +1105,10 @@ private static void resumeDelayedFinalization() { if (resurrectionCriticals == null) { resurrectionCriticals = new IdentityHashMap<>(); } - /* add post-finalization process (and cancel pending suspension process if any) */ - try { - synchronized(postFinalizationProcessRemove) { - postFinalizationProcessRemove.remove( - DelayedFinalizationProcess.defaultInstance); - if (postFinalizationProcessRemove.isEmpty()) { - postFinalizationProcessRemove = null; - } - } - } catch (NullPointerException npe) {} + /* add post finalization process (and cancel pending suspension process if any) */ + synchronized (postFinalizationProcessRemove) { + postFinalizationProcessRemove.remove(DelayedFinalizationProcess.defaultInstance); + } if (indexOfPostFinalizationProcess( DelayedFinalizationProcess.defaultInstance) == -1) { registerPostFinalizationProcess( @@ -1167,6 +1153,7 @@ private static class PostFinalizationProcessor implements Runnable { protected static PostFinalizationProcessor defaultInstance = new PostFinalizationProcessor(); + @Override public void run() { /* We wait until last postFinalizationTimestamp is at least timeOut ago. * This should only be measured when openFinalizeCount is zero. @@ -1199,8 +1186,8 @@ public void run() { /** *

    - * Registers a process that will be called before any finalization during gc-run - * takes place ("finalization" refers to Jython-style finalizers ran by + * Registers a process that will be called before any finalization during gc run + * takes place ("finalization" refers to Jython style finalizers ran by * {@link org.python.core.finalization.FinalizeTrigger}s; * to care for other finalizers these must call * {@code gc.notifyPreFinalization()} before anything else is done and @@ -1216,10 +1203,10 @@ public void run() { *

    *

    * The only guarantee is that {@link java.lang.ref.PhantomReference}s are enqueued - * after finalization of their referents, but this happens in another gc-cycle then. + * after finalization of their referents, but this happens in another gc cycle then. *

    *

    - * Actually there are still situations that can cause pre-finalization process to + * Actually there are still situations that can cause pre finalization process to * run again during finalization phase. This can happen if external frameworks use * their own finalizers. This can be cured by letting these finalizers call * {@code gc.notifyPreFinalization()} before anything else is done and @@ -1241,64 +1228,41 @@ public static void registerPreFinalizationProcess(Runnable process) { */ public static void registerPreFinalizationProcess(Runnable process, int index) { while (true) { - try { - synchronized (preFinalizationProcess) { - preFinalizationProcess.add(index < 0 ? - index+preFinalizationProcess.size()+1 : index, process); - } - return; - } catch (NullPointerException npe) { - preFinalizationProcess = new ArrayList<>(1); + synchronized (preFinalizationProcess) { + preFinalizationProcess.add(index < 0 ? index + preFinalizationProcess.size() + 1 : index, process); } + return; } } public static int indexOfPreFinalizationProcess(Runnable process) { - try { - synchronized (preFinalizationProcess) { - return preFinalizationProcess.indexOf(process); - } - } catch (NullPointerException npe) { - return -1; + synchronized (preFinalizationProcess) { + return preFinalizationProcess.indexOf(process); } } public static boolean unregisterPreFinalizationProcess(Runnable process) { - try { - synchronized (preFinalizationProcess) { - boolean result = preFinalizationProcess.remove(process); - if (result && preFinalizationProcess.isEmpty()) { - preFinalizationProcess = null; - } - return result; - } - } catch (NullPointerException npe) { - return false; + synchronized (preFinalizationProcess) { + return preFinalizationProcess.remove(process); } } /** * Useful if a process wants to remove another one or itself during its execution. - * This asynchronous unregister method circumvents the synchronized-state on - * pre-finalization process list. + * This asynchronous unregister method circumvents the synchronized state on + * pre finalization process list. */ public static void unregisterPreFinalizationProcessAfterNextRun(Runnable process) { - while (true) { - try { - synchronized (preFinalizationProcessRemove) { - preFinalizationProcessRemove.add(process); - } - return; - } catch (NullPointerException npe) { - preFinalizationProcessRemove = new ArrayList<>(1); - } + synchronized (preFinalizationProcessRemove) { + preFinalizationProcessRemove.add(process); } + return; } /** *

    - * Registers a process that will be called after all finalization during gc-run - * is done ("finalization" refers to Jython-style finalizers ran by + * Registers a process that will be called after all finalization during gc run + * is done ("finalization" refers to Jython style finalizers ran by * {@link org.python.core.finalization.FinalizeTrigger}s; * to care for other finalizers these must call * {@code gc.notifyPreFinalization()} before anything else is done and @@ -1315,7 +1279,7 @@ public static void unregisterPreFinalizationProcessAfterNextRun(Runnable process *

    * The only guarantee is that {@link java.lang.ref.PhantomReference}s are * enqueued after finalization of the referents, but this - * happens - however - in another gc-cycle then. + * happens - however - in another gc cycle then. *

    *

    * There are situations that can cause post finalization process to run @@ -1339,58 +1303,31 @@ public static void registerPostFinalizationProcess(Runnable process) { * See doc of {@link #registerPostFinalizationProcess(Runnable)}. */ public static void registerPostFinalizationProcess(Runnable process, int index) { - while (true) { - try { - synchronized (postFinalizationProcess) { - postFinalizationProcess.add(index < 0 ? - index+postFinalizationProcess.size()+1 : index, process); - } - return; - } catch (NullPointerException npe) { - postFinalizationProcess = new ArrayList<>(1); - } + synchronized (postFinalizationProcess) { + postFinalizationProcess.add(index < 0 ? index + postFinalizationProcess.size() + 1 : index, process); } } public static int indexOfPostFinalizationProcess(Runnable process) { - try { - synchronized (postFinalizationProcess) { - return postFinalizationProcess.indexOf(process); - } - } catch (NullPointerException npe) { - return -1; + synchronized (postFinalizationProcess) { + return postFinalizationProcess.indexOf(process); } } public static boolean unregisterPostFinalizationProcess(Runnable process) { - try { - synchronized (postFinalizationProcess) { - boolean result = postFinalizationProcess.remove(process); - if (result && postFinalizationProcess.isEmpty()) { - postFinalizationProcess = null; - } - return result; - } - } catch (NullPointerException npe) { - return false; + synchronized (postFinalizationProcess) { + return postFinalizationProcess.remove(process); } } /** * Useful if a process wants to remove another one or itself during its execution. - * This asynchronous unregister method circumvents the synchronized-state on - * post-finalization process list. + * This asynchronous unregister method circumvents the synchronized state on + * post finalization process list. */ public static void unregisterPostFinalizationProcessAfterNextRun(Runnable process) { - while (true) { - try { - synchronized (postFinalizationProcessRemove) { - postFinalizationProcessRemove.add(process); - } - return; - } catch (NullPointerException npe) { - postFinalizationProcessRemove = new ArrayList<>(1); - } + synchronized (postFinalizationProcessRemove) { + postFinalizationProcessRemove.add(process); } } @@ -1398,13 +1335,13 @@ public static void notifyPreFinalization() { long callTime = System.currentTimeMillis(); /* * This section is experimental and kept for further investigation. In theory, it can - * prevent potential problems in JyNI-gc, if a gc-run overlaps the previous run's - * post-finalization phase. However it currently breaks gc-tests, so is out-commented - * so far. In practical sense, JyNI's gc-support also works fine without it so far. + * prevent potential problems in JyNI gc, if a gc run overlaps the previous run's + * post finalization phase. However it currently breaks gc tests, so is out commented + * so far. In practical sense, JyNI's gc support also works fine without it so far. */ // if (postFinalizationPending) { // if ((gcFlags & VERBOSE_COLLECT) != 0) { -// writeDebug("gc", "waiting for pending post-finalization process."); +// writeDebug("gc", "waiting for pending post finalization process."); // } // /* It is important to have the while (which is actually an "if" since the // * InterruptedException is very unlikely to occur) *inside* the synchronized @@ -1420,12 +1357,12 @@ public static void notifyPreFinalization() { // } // } // if ((gcFlags & VERBOSE_COLLECT) != 0) { -// writeDebug("gc", "post-finalization finished."); +// writeDebug("gc", "post finalization finished."); // } // } // /* // * Increment of openFinalizeCount must not happen before waiting for pending -// * post-finalization process is done. Otherwise PostFinalizationProcessor can +// * post finalization process is done. Otherwise PostFinalizationProcessor can // * be waiting for a neutral openFinalizeCount, causing a deadlock. // */ ++openFinalizeCount; @@ -1433,7 +1370,6 @@ public static void notifyPreFinalization() { < postFinalizationTimeOut) { return; } - try { synchronized(preFinalizationProcess) { for (Runnable r: preFinalizationProcess) { try { @@ -1443,21 +1379,12 @@ public static void notifyPreFinalization() { +preProcessError); } } - try { synchronized (preFinalizationProcessRemove) { preFinalizationProcess.removeAll(preFinalizationProcessRemove); - preFinalizationProcessRemove = null; + preFinalizationProcessRemove.clear(); } - if (preFinalizationProcess.isEmpty()) { - preFinalizationProcess = null; - } - } catch (NullPointerException npe0) {} } - } catch (NullPointerException npe) { - preFinalizationProcessRemove = null; - } - try { synchronized(postFinalizationProcess) { if (!postFinalizationProcess.isEmpty() && postFinalizationProcessor == null) { @@ -1467,7 +1394,6 @@ public static void notifyPreFinalization() { postFinalizationProcessor.start(); } } - } catch (NullPointerException npe) {} } public static void notifyPostFinalization() { @@ -1479,28 +1405,19 @@ public static void notifyPostFinalization() { } protected static void postFinalizationProcess() { - try { - synchronized(postFinalizationProcess) { - for (Runnable r: postFinalizationProcess) { - try { - r.run(); - } catch (Exception postProcessError) { - System.err.println("Finalization postprocess "+r+" caused error:"); - System.err.println(postProcessError); - } - } + synchronized (postFinalizationProcess) { + for (Runnable r : postFinalizationProcess) { try { - synchronized (postFinalizationProcessRemove) { - postFinalizationProcess.removeAll(postFinalizationProcessRemove); - postFinalizationProcessRemove = null; - } - if (postFinalizationProcess.isEmpty()) { - postFinalizationProcess = null; - } - } catch (NullPointerException npe0) {} + r.run(); + } catch (Exception postProcessError) { + System.err.println("Finalization postprocess " + r + " caused error:"); + System.err.println(postProcessError); + } + } + synchronized (postFinalizationProcessRemove) { + postFinalizationProcess.removeAll(postFinalizationProcessRemove); + postFinalizationProcessRemove.clear(); } - } catch (NullPointerException npe) { - postFinalizationProcessRemove = null; } } //--------------end of Finalization preprocess/postprocess section------------- @@ -1509,7 +1426,7 @@ protected static void postFinalizationProcess() { //--------------Monitoring section--------------------------------------------- - + public static void monitorObject(PyObject ob) { monitorObject(ob, false); } @@ -1537,23 +1454,19 @@ public static void monitorObject(PyObject ob, boolean initString) { gcTrash = new ReferenceQueue<>(); } while (true) { - try { - synchronized(monitoredObjects) { - if (!isMonitored(ob)) { - CycleMarkAttr cm = new CycleMarkAttr(); - JyAttribute.setAttr(ob, JyAttribute.GC_CYCLE_MARK_ATTR, cm); - WeakReferenceGC refPut = new WeakReferenceGC(ob, gcTrash); - if (initString) { - refPut.initStr(ob); - } - monitoredObjects.add(refPut); - cm.monitored = true; + synchronized (monitoredObjects) { + if (!isMonitored(ob)) { + CycleMarkAttr cm = new CycleMarkAttr(); + JyAttribute.setAttr(ob, JyAttribute.GC_CYCLE_MARK_ATTR, cm); + WeakReferenceGC refPut = new WeakReferenceGC(ob, gcTrash); + if (initString) { + refPut.initStr(ob); } + monitoredObjects.add(refPut); + cm.monitored = true; } - return; - } catch (NullPointerException npe) { - monitoredObjects = new HashSet(); } + return; } } @@ -1563,44 +1476,32 @@ public static void monitorObject(PyObject ob, boolean initString) { * exists for bare debugging purposes. */ public static WeakReferenceGC getMonitorReference(PyObject ob) { - try { - synchronized(monitoredObjects) { - for (WeakReferenceGC ref: monitoredObjects) { - if (ref.equals(ob)) { - return ref; - } + synchronized (monitoredObjects) { + for (WeakReferenceGC ref : monitoredObjects) { + if (ref.equals(ob)) { + return ref; } } - } catch (NullPointerException npe) {} + } return null; } public static boolean isMonitoring() { - try { - synchronized(monitoredObjects) { - return !monitoredObjects.isEmpty(); - } - } catch (NullPointerException npe) { - return false; + synchronized (monitoredObjects) { + return !monitoredObjects.isEmpty(); } } public static boolean isMonitored(PyObject ob) { - try { - synchronized(monitoredObjects) { - WeakrefGCCompareDummy.defaultInstance.setCompare(ob); - boolean result = monitoredObjects.contains( - WeakrefGCCompareDummy.defaultInstance); - WeakrefGCCompareDummy.defaultInstance.clearCompare(); - return result; - } - } catch (NullPointerException npe) { - return false; + synchronized (monitoredObjects) { + WeakrefGCCompareDummy.defaultInstance.setCompare(ob); + boolean result = monitoredObjects.contains(WeakrefGCCompareDummy.defaultInstance); + WeakrefGCCompareDummy.defaultInstance.clearCompare(); + return result; } } public static boolean unmonitorObject(PyObject ob) { - try { synchronized(monitoredObjects) { WeakrefGCCompareDummy.defaultInstance.setCompare(ob); WeakReferenceGC rem = getMonitorReference(ob); @@ -1618,39 +1519,29 @@ public static boolean unmonitorObject(PyObject ob) { } return result; } - } catch (NullPointerException npe) { - return false; - } } public static void unmonitorAll() { - try { - synchronized(monitoredObjects) { - FinalizeTrigger ft; - for (WeakReferenceGC mo: monitoredObjects) { - PyObject rfrt = mo.get(); - if (rfrt != null) { - JyAttribute.delAttr(rfrt, JyAttribute.GC_CYCLE_MARK_ATTR); - ft = (FinalizeTrigger) - JyAttribute.getAttr(rfrt, JyAttribute.FINALIZE_TRIGGER_ATTR); - if (ft != null) { - ft.flags &= ~FinalizeTrigger.NOTIFY_GC_FLAG; - } + synchronized (monitoredObjects) { + FinalizeTrigger ft; + for (WeakReferenceGC mo : monitoredObjects) { + PyObject rfrt = mo.get(); + if (rfrt != null) { + JyAttribute.delAttr(rfrt, JyAttribute.GC_CYCLE_MARK_ATTR); + ft = (FinalizeTrigger) JyAttribute.getAttr(rfrt, JyAttribute.FINALIZE_TRIGGER_ATTR); + if (ft != null) { + ft.flags &= ~FinalizeTrigger.NOTIFY_GC_FLAG; } - mo.clear(); } - monitoredObjects.clear(); + mo.clear(); } - } catch (NullPointerException npe) { + monitoredObjects.clear(); } } public static void stopMonitoring() { setMonitorGlobal(false); - if (monitoredObjects != null) { - unmonitorAll(); - monitoredObjects = null; - } + unmonitorAll(); } public static boolean getMonitorGlobal() { @@ -1669,7 +1560,7 @@ public static void setMonitorGlobal(boolean flag) { /** - * Gets the current Jython-specific gc-flags. + * Gets the current Jython specific gc flags. * * @see #MONITOR_GLOBAL * @see #DONT_FINALIZE_CYCLIC_GARBAGE @@ -1700,17 +1591,17 @@ public static short getJythonGCFlags() { } /** - * Sets the current Jython-specific gc-flags. + * Sets the current Jython specific gc flags. *
    * {@code flags} is a {@code short} and can have the following bits turned on:
    *
    * {@link #MONITOR_GLOBAL} - Automatically monitors all PyObjects created from now on.
    * {@link #DONT_FINALIZE_CYCLIC_GARBAGE} - Adds cyclic finalizable PyObjects to {@link #garbage}.
    * {@link #PRESERVE_WEAKREFS_ON_RESURRECTION} - Keeps weak references alive if the referent is resurrected.
    - * {@link #DONT_FINALIZE_RESURRECTED_OBJECTS} - + * {@link #DONT_FINALIZE_RESURRECTED_OBJECTS} - * Emulates CPython behavior regarding resurrected objects and finalization.
    - * {@link #DONT_TRAVERSE_BY_REFLECTION} - Inhibits reflection-based traversion.
    - * {@link #SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING} - + * {@link #DONT_TRAVERSE_BY_REFLECTION} - Inhibits reflection-based traversal.
    + * {@link #SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING} - * Suppress warnings for PyObjects that neither implement {@link org.python.core.Traverseproc} nor * are marked as {@link org.python.core.Untraversable}.
    * {@link #USE_PY_WRITE_DEBUG} - uses {@link org.python.core.Py#writeDebug(String, String)} for @@ -1821,15 +1712,14 @@ private static void notifyAbortFinalize(PyObject abort, boolean cyclic) { } /** - * Does nothing in Jython as Java-gc is always enabled. + * Does nothing in Jython as Java gc is always enabled. */ public static void enable() {} /** * Not supported by Jython. - * Throws {@link org.python.core.Py#NotImplementedError}. * - * @throws org.python.core.Py.NotImplementedError + * @throws PyException {@code NotImplementedError} */ public static void disable() { throw Py.NotImplementedError("can't disable Java GC"); @@ -1842,9 +1732,9 @@ public static void disable() { /** * The generation parameter is only for compatibility with - * CPython {@link gc.collect()} and is ignored. + * CPython {@link #collect()} and is ignored. * @param generation (ignored) - * @return Collected monitored cyclic trash-objects or + * @return Collected monitored cyclic trash objects or * {@code gc.UNKNOWN_COUNT} if nothing is monitored or -1 if * an error occurred and collection did not complete. * @see #collect() @@ -1852,7 +1742,7 @@ public static void disable() { public static int collect(int generation) { return collect(); } - + private static boolean needsTrashPrinting() { return ((debugFlags & DEBUG_COLLECTABLE) != 0 || (debugFlags & DEBUG_UNCOLLECTABLE) != 0) && @@ -1868,10 +1758,10 @@ private static boolean needsCollectBuffer() { * If no objects are monitored, this just delegates to * {@code System.gc()} and returns {@link #UNKNOWN_COUNT} as a * non-erroneous default value. If objects are monitored, - * it emulates a synchronous gc-run in the sense that it waits + * it emulates a synchronous gc run in the sense that it waits * until all collected monitored objects were finalized. - * - * @return Number of collected monitored cyclic trash-objects + * + * @return Number of collected monitored cyclic trash objects * or {@link #UNKNOWN_COUNT} if nothing is monitored or -1 * if an error occurred and collection did not complete. * @see #UNKNOWN_COUNT @@ -1884,7 +1774,7 @@ public static int collect() { cme.printStackTrace(); } catch (NullPointerException npe) { npe.printStackTrace(); - } + } return -1; } @@ -1911,7 +1801,7 @@ private static int collect_intern() { } /* We must fail fast in this case to avoid deadlocks. * Deadlock would for instance occur if a finalizer calls - * gc.collect (like is done in some tests in test_gc). + * gc.collect (like is done in some tests in test_gc). * Former version: throw new IllegalStateException("GC is already running."); */ return -1; /* better not throw exception here, as calling code @@ -1947,9 +1837,9 @@ private static int collect_intern() { ++gcMonitoredRunCount; delayedFinalizationMode = MARK_REACHABLE_CRITICALS; notifyRerun = false; - + int[] stat = {0, 0}; - + syncCollect(stat, (debugFlags & DEBUG_STATS) != 0); delayedFinalizationMode = NOTIFY_FOR_RERUN; @@ -2045,7 +1935,7 @@ private static void syncCollect(int[] stat, boolean debugStat) { } } - /* Typically this line causes a gc-run: */ + /* Typically this line causes a gc run: */ cyclicLookup = removeNonCyclicWeakRefs(monitoredObjects); cyclic = new HashSet<>(cyclicLookup.values()); if (debugStat) { @@ -2075,20 +1965,20 @@ private static void syncCollect(int[] stat, boolean debugStat) { System.err.println("Finalize wait count should be initially 0!"); finalizeWaitCount = 0; } - + /* We tidy up a bit... (Because it is not unlikely that - * the preparation-stuff done so far has caused a gc-run.) + * the preparation stuff done so far has caused a gc run.) * This is not entirely safe as gc could interfere with * this process at any time again. Since this is intended * for debugging, this solution is sufficient in practice. * Maybe we will include more mechanisms to ensure safety * in the future. */ - + try { trash = gcTrash.remove(initWaitTime); if (trash != null && (gcFlags & VERBOSE_COLLECT) != 0) { - writeDebug("gc", "monitored objects from interferring gc-run found."); + writeDebug("gc", "monitored objects from interferring gc run found."); } } catch (InterruptedException ie) { trash = null; @@ -2116,8 +2006,8 @@ private static void syncCollect(int[] stat, boolean debugStat) { } cyclicLookup = null; List collectBuffer; - - /* The following out-commented block is a nice idea to sync gc in a more + + /* The following out commented block is a nice idea to sync gc in a more * elegant way. Unfortunately it proved infeasible because MXBean appears * to be no reliable measurement for gc to have finished enqueueing trash. * We leave it here to document this failed approach for future generations, @@ -2128,7 +2018,7 @@ private static void syncCollect(int[] stat, boolean debugStat) { // reason for it. // collectSyncViaMXBean uses inofficial API, i.e. classes from com.sun.management. // In case that a JVM does not provide this API, we have a less elegant fallback - // at hand, which is based on a sentinel- and timeout-technique. + // at hand, which is based on a sentinel and timeout technique. try { collectBuffer = collectSyncViaMXBean(stat, cyclic); } catch (NoClassDefFoundError ncdfe) { @@ -2141,10 +2031,10 @@ private static void syncCollect(int[] stat, boolean debugStat) { collectBuffer = collectSyncViaSentinel(stat, cyclic); //lockPostFinalization assures that postFinalization process - //only runs once per syncCollect-call. + //only runs once per syncCollect call. lockPostFinalization = false; if (postFinalizationProcessor != null) { - //abort the remaining wait-time if a postFinalizationProcessor is waiting + //abort the remaining wait time if a postFinalizationProcessor is waiting postFinalizationProcessor.interrupt(); } waitingForFinalizers = true; @@ -2177,22 +2067,22 @@ private static void syncCollect(int[] stat, boolean debugStat) { * are stored in gc.garbage, but it actually stores only * those uncollectable objects that have finalizers. * In contrast to that the uncollectable counting and - * listing related to DEBUG_X-flags also counts/lists + * listing related to DEBUG_X flags also counts/lists * objects that participate in a cycle with uncollectable * finalizable objects. - * + * * Comprehension: * An object is uncollectable if it is in a ref cycle and * has a finalizer. - * + * * CPython - * + * * - counts and prints the whole uncollectable cycle in context - * of DEBUG_X-flags. - * + * of DEBUG_X flags. + * * - stores only those objects from the cycle that actually have * finalizers in gc.garbage. - * + * * While slightly contradictory to the doc, we reproduce this * behavior here. */ @@ -2247,8 +2137,8 @@ private static void syncCollect(int[] stat, boolean debugStat) { } /* - * The following out-commented section belongs to the out-commented - * block on MXBean-based GC sync somewhere above. + * The following out commented section belongs to the out commented + * block on MXBean based GC sync somewhere above. * We keep it here to document this failed approach and to enable * future developers to quickly reproduce and analyse this failure. @@ -2323,7 +2213,7 @@ private static List collectSyncViaMXBean(int[] stat, Set initialGCCounts[i]; ++outstandingNotifications; if (waitForGCNotification[i]) { - // at least one counter should change if a gc-run occurred. + // at least one counter should change if a gc run occurred. gcRunDetected = true; } } @@ -2348,7 +2238,7 @@ private static List collectSyncViaMXBean(int[] stat, Set collectSyncViaSentinel(int[] stat, Set + * Copied from CPython doc:
    *
    * Set the garbage collection debugging flags. Debugging information is * written to {@code System.err}.
    *
    - * {@flags} flags is an {@code int}eger and can have the following bits turned on:
    + * {@code flags} flags is an {@code int}eger and can have the following bits turned on:
    *
    * {@link #DEBUG_STATS} - Print statistics during collection.
    * {@link #DEBUG_COLLECTABLE} - Print collectable objects found.
    @@ -2529,7 +2418,7 @@ public static void set_debug(int flags) { } /** - * Copied from CPython-doc:
    + * Copied from CPython doc:
    *
    * Get the garbage collection debugging flags. */ @@ -2539,9 +2428,8 @@ public static int get_debug() { /** * Not supported by Jython. - * Throws {@link org.python.core.Py#NotImplementedError}. * - * @throws org.python.core.Py.NotImplementedError + * @throws PyException {@code NotImplementedError} */ public static void set_threshold(PyObject[] args, String[] kwargs) { throw Py.NotImplementedError("not applicable to Java GC"); @@ -2549,9 +2437,8 @@ public static void set_threshold(PyObject[] args, String[] kwargs) { /** * Not supported by Jython. - * Throws {@link org.python.core.Py#NotImplementedError}. * - * @throws org.python.core.Py.NotImplementedError + * @throws PyException {@code NotImplementedError} */ public static PyObject get_threshold() { throw Py.NotImplementedError("not applicable to Java GC"); @@ -2561,10 +2448,9 @@ public static PyObject get_threshold() { * Only works reliably if {@code monitorGlobal} is active, as it depends on * monitored objects to search for referrers. It only finds referrers that * properly implement the traverseproc mechanism (unless reflection-based - * traversion is activated and works stable). - * Throws {@link org.python.core.Py#NotImplementedError}. + * traversal is activated and works stable). * - * @throws org.python.core.Py.NotImplementedError + * @throws PyException {@code NotImplementedError} */ public static PyObject get_objects() { if (!isMonitoring()) { @@ -2588,7 +2474,7 @@ public static PyObject get_objects() { * Only works reliably if {@code monitorGlobal} is active, as it depends on * monitored objects to search for referrers. It only finds referrers that * properly implement the traverseproc mechanism (unless reflection-based - * traversion is activated and works stable). + * traversal is activated and works stable). * Further note that the resulting list will contain referrers in no specific * order and may even include duplicates. */ @@ -2628,7 +2514,7 @@ public static PyObject get_referrers(PyObject[] args, String[] kwargs) { /** * Only works reliably if all objects in args properly - * implement the Traverseproc mechanism (unless reflection-based traversion + * implement the Traverseproc mechanism (unless reflection-based traversal * is activated and works stable). * Further note that the resulting list will contain referents in no * specific order and may even include duplicates. @@ -2661,19 +2547,19 @@ public static PyObject is_tracked(PyObject[] args, String[] kwargs) { /** * Returns all objects from {@code pool} that are part of reference cycles as a new set. - * If a reference-cycle is not entirely contained in {@code pool}, it will be entirely + * If a reference cycle is not entirely contained in {@code pool}, it will be entirely * contained in the resulting set, i.e. missing participants will be added. * This method completely operates on weak references to ensure that the returned - * set does not manipulate gc-behavior. - * - * Note that this method is not thread-safe. Within the gc-module it is only used - * by the collect-method which ensures thread-safety by a synchronized block. + * set does not manipulate gc behavior. + * + * Note that this method is not threadsafe. Within the gc module it is only used + * by the collect method, which ensures threadsafety by a synchronized block. */ private static IdentityHashMap removeNonCyclicWeakRefs(Iterable pool) { @SuppressWarnings("unchecked") IdentityHashMap[] pools = new IdentityHashMap[2]; - + pools[0] = new IdentityHashMap(); pools[1] = new IdentityHashMap(); PyObject referent; @@ -2691,8 +2577,9 @@ public static PyObject is_tracked(PyObject[] args, String[] kwargs) { /* this means the pool is already entirely traversable */ for (WeakReferenceGC ref: pool) { referent = ref.get(); - if (referent != null) - pools[0].put(referent, ref); + if (referent != null) { + pools[0].put(referent, ref); + } } } IdentityHashMap tmp; @@ -2760,7 +2647,7 @@ private static Set findReachables(Iterable pool) { pools[1] = new IdentityHashMap(); IdentityHashMap tmp; IdentityHashMap toProcess = new IdentityHashMap<>(); - + /* We complete pools[0] with all reachable objects. * Note the difference to the implementation in removeNonCyclic. * There pools[0] was initialized with the contents of pool and @@ -2789,19 +2676,19 @@ private static Set findReachables(Iterable pool) { } /** - * Returns all objects from {@code pool} that are part of reference-cycles as a new set. - * If a reference-cycle is not entirely contained in {@code pool}, it will be entirely + * Returns all objects from {@code pool} that are part of reference cycles as a new set. + * If a reference cycle is not entirely contained in {@code pool}, it will be entirely * contained in the resulting set, i.e. missing participants will be added. * This method completely operates on weak references to ensure that the returned - * set does not manipulate gc-behavior. - * - * Note that this method is not thread-safe. Within the gc-module it is only used - * by the collect-method which ensures thread-safety by a synchronized block. + * set does not manipulate gc behavior. + * + * Note that this method is not threadsafe. Within the gc module it is only used + * by the collect method which ensures threadsafety by a synchronized block. */ private static Set removeNonCyclic(Iterable pool) { @SuppressWarnings("unchecked") IdentityHashMap[] pools = new IdentityHashMap[2]; - + pools[0] = new IdentityHashMap(); pools[1] = new IdentityHashMap(); if (monitorNonTraversable) { @@ -2821,7 +2708,7 @@ private static Set removeNonCyclic(Iterable pool) { } IdentityHashMap tmp; IdentityHashMap toProcess = new IdentityHashMap<>(); - + /* We complete pools[0] with all reachable objects. */ for (PyObject obj: pools[0].keySet()) { traverse(obj, ReachableFinder.defaultInstance, pools); @@ -2880,7 +2767,7 @@ public static void markCyclicObjects(PyObject start, boolean uncollectable) { return; } /* Search contains the cyclic objects that participate in a cycle with start, - * i.e. which are reachable from start AND can reach start. + * i.e. which are reachable from start AND can reach start. * Mark these... */ CycleMarkAttr cm; @@ -2964,7 +2851,7 @@ private static IdentityHashMap findCyclicObjectsIntern(PyObj * {@link org.python.core.TraverseprocDerived#traverseDerived(Visitproc, Object)}. * If {@code ob} neither implements {@link org.python.core.Traverseproc} nor * {@link org.python.core.Traverseproc} and is not annotated with - * {@link org.python.core.Untraversable}, reflection-based traversion via + * {@link org.python.core.Untraversable}, reflection-based traversal via * {@link #traverseByReflection(Object, Visitproc, Object)} may be attempted * according to {@link #DONT_TRAVERSE_BY_REFLECTION}. * @@ -2980,12 +2867,16 @@ public static int traverse(PyObject ob, Visitproc visit, Object arg) { if (ob instanceof Traverseproc) { retVal = ((Traverseproc) ob).traverse(visit, arg); traversed = true; - if (retVal != 0) return retVal; + if (retVal != 0) { + return retVal; + } } if (ob instanceof TraverseprocDerived) { retVal = ((TraverseprocDerived) ob).traverseDerived(visit, arg); traversed = true; - if (retVal != 0) return retVal; + if (retVal != 0) { + return retVal; + } } boolean justAddedWarning = false; if ((gcFlags & SUPPRESS_TRAVERSE_BY_REFLECTION_WARNING) == 0) { @@ -3002,7 +2893,7 @@ public static int traverse(PyObject ob, Visitproc visit, Object arg) { reflectionWarnedClasses.add(ob.getClass()); justAddedWarning = true; } - Py.writeWarning("gc", "The PyObject-subclass "+ob.getClass().getName()+"\n" + + Py.writeWarning("gc", "The PyObject subclass "+ob.getClass().getName()+"\n" + "should either implement Traverseproc or be marked with the\n" + "@Untraversable annotation. See instructions in\n" + "javadoc of org.python.core.Traverseproc.java."); @@ -3043,7 +2934,7 @@ public static int traverse(PyObject ob, Visitproc visit, Object arg) { * If a field is a PyObject, it is passed to {@code visit}. * and recursion ends in that branch. * If a field is an array, the elements are checked whether - * they are PyObjects. {@code PyObject}-elements are passed to + * they are PyObjects. {@code PyObject} elements are passed to * {@code visit}. Elements that are arrays themselves are again * processed elementwise and so on. *

    @@ -3131,7 +3022,7 @@ private static int traverseByReflectionIntern(Object ob, * This method checks via type-checking-only, whether an object * of the given class can in principle hold a ref to a {@code PyObject}. * Especially if arrays are involved, this can safe a lot performance. - * For now, no generic type-info is exploited. + * For now, no generic type info is exploited. *

    *

    * If {@code actual} is true, the answer will hold for an object @@ -3143,11 +3034,11 @@ private static int traverseByReflectionIntern(Object ob, *

    * One should call with {@code actual == true}, if cls was obtained * by {@code ob.getClass()} and with {@code actual == false}, if cls - * was obtained as a field-type or component-type of an array. + * was obtained as a field type or component type of an array. *

    */ public static boolean canLinkToPyObject(Class cls, boolean actual) { - /* At first some quick (fail-fast/succeed-fast)-checks: */ + /* At first some quick (fail fast/succeed fast) checks: */ if (quickCheckCannotLinkToPyObject(cls)) { return false; } @@ -3164,7 +3055,7 @@ public static boolean canLinkToPyObject(Class cls, boolean actual) { return canLinkToPyObject(cls.getComponentType(), false); } Class cls2 = cls; - + /* Fail fast if no fields exist in cls: */ int fieldCount = cls2.getDeclaredFields().length; while (fieldCount == 0 && cls2 != Object.class) { @@ -3279,6 +3170,7 @@ private static class ReferentsFinder implements Visitproc { * Expects arg to be a list-like {@code PyObject} where the * referents will be inserted. */ + @Override public int visit(PyObject object, Object arg) { ((org.python.core.PySequenceList) arg).pyadd(object); return 0; @@ -3302,6 +3194,7 @@ private static class ReachableFinder implements Visitproc { * Expects arg to be a list-like {@code PyObject} where the * referents will be inserted. */ + @Override @SuppressWarnings("unchecked") public int visit(PyObject object, Object arg) { IdentityHashMap[] reachSearch = @@ -3317,10 +3210,11 @@ public int visit(PyObject object, Object arg) { private static class ReachableFinderWeakRefs implements Visitproc { public static ReachableFinderWeakRefs defaultInstance = new ReachableFinderWeakRefs(); + @Override @SuppressWarnings("unchecked") public int visit(PyObject object, Object arg) { if (isTraversable(object)) { - IdentityHashMap[] pools = + IdentityHashMap[] pools = (IdentityHashMap[]) arg; WeakReferenceGC ref = pools[0].get(object); if (ref == null) { @@ -3341,6 +3235,7 @@ private static class ReferrerFinder implements Visitproc { * {@code arg[0]} and the destination list (a list-like {@code PyObject} * where the referrers will be inserted) at {@code arg[1]}. */ + @Override public int visit(PyObject object, Object arg) { if (((PyObject[]) arg)[0].__eq__(object).__nonzero__()) { ((org.python.core.PySequenceList) ((PyObject[]) arg)[1]).pyadd(object); @@ -3351,13 +3246,14 @@ public int visit(PyObject object, Object arg) { /** * Like {@code RefInListFinder} this visitproc looks whether the traversed object - * refers to one of the objects in a given set. Here we perform fail-fast + * refers to one of the objects in a given set. Here we perform fail fast * behavior. This method is useful if one is not interested in the referrers, * but only wants to know (quickly) whether a connection exists or not. */ private static class RefersToSetFinder implements Visitproc { public static RefersToSetFinder defaultInstance = new RefersToSetFinder(); + @Override @SuppressWarnings("unchecked") public int visit(PyObject object, Object arg) { return ((Set) arg).contains(object) ? 1 : 0; @@ -3367,7 +3263,7 @@ public int visit(PyObject object, Object arg) { /** * This visitproc looks whether an object refers to one of the objects in * a given set.
    - * {@code arg} must be a 2-component-array of + * {@code arg} must be a 2-component array of * {@code HashMap}. * These maps are actually used as sets, but resolve the strongref/weakref * views to the objects.
    @@ -3387,6 +3283,7 @@ private static class RefInListFinder implements Visitproc { * Expects {@code arg} to be a 2-component array of * {@link java.util.Map}s. */ + @Override public int visit(PyObject object, Object arg) { @SuppressWarnings("unchecked") IdentityHashMap[] pools = @@ -3408,6 +3305,7 @@ private static class ObjectInListFinder implements Visitproc { * Expects {@code arg} to be a 2-component array of * {@link java.util.Map}s. */ + @Override public int visit(PyObject object, Object arg) { @SuppressWarnings("unchecked") IdentityHashMap[] pools = diff --git a/src/org/python/modules/itertools/PyTeeIteratorDerived.java b/src/org/python/modules/itertools/PyTeeIteratorDerived.java index 09b212a1d..9b2b39e20 100644 --- a/src/org/python/modules/itertools/PyTeeIteratorDerived.java +++ b/src/org/python/modules/itertools/PyTeeIteratorDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/chainDerived.java b/src/org/python/modules/itertools/chainDerived.java index a743979ab..f96c037dc 100644 --- a/src/org/python/modules/itertools/chainDerived.java +++ b/src/org/python/modules/itertools/chainDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/combinationsDerived.java b/src/org/python/modules/itertools/combinationsDerived.java index 9c67ba3f6..f3a8df793 100644 --- a/src/org/python/modules/itertools/combinationsDerived.java +++ b/src/org/python/modules/itertools/combinationsDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java index 5b62f1d8d..8b0702e33 100644 --- a/src/org/python/modules/itertools/combinationsWithReplacementDerived.java +++ b/src/org/python/modules/itertools/combinationsWithReplacementDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/compressDerived.java b/src/org/python/modules/itertools/compressDerived.java index 3cfd4d7cc..7808209ef 100644 --- a/src/org/python/modules/itertools/compressDerived.java +++ b/src/org/python/modules/itertools/compressDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/countDerived.java b/src/org/python/modules/itertools/countDerived.java index 8caa57666..b428ced79 100644 --- a/src/org/python/modules/itertools/countDerived.java +++ b/src/org/python/modules/itertools/countDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/cycleDerived.java b/src/org/python/modules/itertools/cycleDerived.java index 978c5a03b..5129522cc 100644 --- a/src/org/python/modules/itertools/cycleDerived.java +++ b/src/org/python/modules/itertools/cycleDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/dropwhileDerived.java b/src/org/python/modules/itertools/dropwhileDerived.java index be2aa15fa..10c325d7f 100644 --- a/src/org/python/modules/itertools/dropwhileDerived.java +++ b/src/org/python/modules/itertools/dropwhileDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/groupbyDerived.java b/src/org/python/modules/itertools/groupbyDerived.java index 64b1e726d..99b3ce103 100644 --- a/src/org/python/modules/itertools/groupbyDerived.java +++ b/src/org/python/modules/itertools/groupbyDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/ifilterDerived.java b/src/org/python/modules/itertools/ifilterDerived.java index d60a8f4b9..c90f0645d 100644 --- a/src/org/python/modules/itertools/ifilterDerived.java +++ b/src/org/python/modules/itertools/ifilterDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/ifilterfalseDerived.java b/src/org/python/modules/itertools/ifilterfalseDerived.java index 2630d3a02..57613d204 100644 --- a/src/org/python/modules/itertools/ifilterfalseDerived.java +++ b/src/org/python/modules/itertools/ifilterfalseDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/imapDerived.java b/src/org/python/modules/itertools/imapDerived.java new file mode 100644 index 000000000..f0ea0147d --- /dev/null +++ b/src/org/python/modules/itertools/imapDerived.java @@ -0,0 +1,1175 @@ +/* Generated file, do not modify. See jython/src/templates/gderived.py. */ +package org.python.modules.itertools; + +import java.io.Serializable; +import org.python.core.*; +import org.python.core.finalization.FinalizeTrigger; +import org.python.core.finalization.FinalizablePyObjectDerived; + +public class imapDerived extends imap implements Slotted,FinalizablePyObjectDerived,TraverseprocDerived { + + public PyObject getSlot(int index) { + return slots[index]; + } + + public void setSlot(int index,PyObject value) { + slots[index]=value; + } + + private PyObject[]slots; + + public void __del_derived__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__del__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(); + } + } + + public void __ensure_finalizer__() { + FinalizeTrigger.ensureFinalizer(this); + } + + /* TraverseprocDerived implementation */ + public int traverseDerived(Visitproc visit,Object arg) { + int retVal; + for(int i=0;i0?1:0; + } + + public boolean __nonzero__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__nonzero__"); + if (impl==null) { + impl=self_type.lookup("__len__"); + if (impl==null) + return super.__nonzero__(); + } + PyObject o=impl.__get__(this,self_type).__call__(); + Class c=o.getClass(); + if (c!=PyInteger.class&&c!=PyBoolean.class) { + throw Py.TypeError(String.format("__nonzero__ should return bool or int, returned %s",self_type.getName())); + } + return o.__nonzero__(); + } + + public boolean __contains__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__contains__"); + if (impl==null) + return super.__contains__(o); + return impl.__get__(this,self_type).__call__(o).__nonzero__(); + } + + public int __len__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__len__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + return res.asInt(); + } + return super.__len__(); + } + + public PyObject __iter__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__iter__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(); + impl=self_type.lookup("__getitem__"); + if (impl==null) + return super.__iter__(); + return new PySequenceIter(this); + } + + public PyObject __iternext__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("next"); + if (impl!=null) { + try { + return impl.__get__(this,self_type).__call__(); + } catch (PyException exc) { + if (exc.match(Py.StopIteration)) + return null; + throw exc; + } + } + return super.__iternext__(); // ??? + } + + public PyObject __finditem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(key); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __finditem__(int key) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + try { + return impl.__get__(this,self_type).__call__(new PyInteger(key)); + } catch (PyException exc) { + if (exc.match(Py.LookupError)) + return null; + throw exc; + } + return super.__finditem__(key); + } + + public PyObject __getitem__(PyObject key) { + // Same as __finditem__, without swallowing LookupErrors. This allows + // __getitem__ implementations written in Python to raise custom + // exceptions (such as subclasses of KeyError). + // + // We are forced to duplicate the code, instead of defining __finditem__ + // in terms of __getitem__. That's because PyObject defines __getitem__ + // in terms of __finditem__. Therefore, we would end with an infinite + // loop when self_type.lookup("__getitem__") returns null: + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> __getitem__ + // + // By duplicating the (short) lookup and call code, we are safe, because + // the call chains will be: + // + // __finditem__ -> super.__finditem__ + // + // __getitem__ -> super.__getitem__ -> __finditem__ -> super.__finditem__ + + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getitem__"); + if (impl!=null) + return impl.__get__(this,self_type).__call__(key); + return super.__getitem__(key); + } + + public void __setitem__(PyObject key,PyObject value) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key,value); + return; + } + super.__setitem__(key,value); + } + + public PyObject __getslice__(PyObject start,PyObject stop,PyObject step) { // ??? + if (step!=null) { + return __getitem__(new PySlice(start,stop,step)); + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__getslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + return impl.__get__(this,self_type).__call__(indices[0],indices[1]); + } + return super.__getslice__(start,stop,step); + } + + public void __setslice__(PyObject start,PyObject stop,PyObject step,PyObject value) { + if (step!=null) { + __setitem__(new PySlice(start,stop,step),value); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1],value); + return; + } + super.__setslice__(start,stop,step,value); + } + + public void __delslice__(PyObject start,PyObject stop,PyObject step) { + if (step!=null) { + __delitem__(new PySlice(start,stop,step)); + return; + } + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delslice__"); + if (impl!=null) { + PyObject[]indices=PySlice.indices2(this,start,stop); + impl.__get__(this,self_type).__call__(indices[0],indices[1]); + return; + } + super.__delslice__(start,stop,step); + } + + public void __delitem__(PyObject key) { // ??? + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delitem__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(key); + return; + } + super.__delitem__(key); + } + + public PyObject __call__(PyObject args[],String keywords[]) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__call__"); + if (impl!=null) { + return impl.__get__(this,self_type).__call__(args,keywords); + } + return super.__call__(args,keywords); + } + + public PyObject __findattr_ex__(String name) { + return Deriveds.__findattr_ex__(this,name); + } + + public void __setattr__(String name,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__setattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name),value); + //CPython does not support instance-acquired finalizers. + //So we don't check for __del__ here. + return; + } + super.__setattr__(name,value); + } + + public void __delattr__(String name) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delattr__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(PyString.fromInterned(name)); + return; + } + super.__delattr__(name); + } + + public PyObject __get__(PyObject obj,PyObject type) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__get__"); + if (impl!=null) { + if (obj==null) + obj=Py.None; + if (type==null) + type=Py.None; + return impl.__get__(this,self_type).__call__(obj,type); + } + return super.__get__(obj,type); + } + + public void __set__(PyObject obj,PyObject value) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__set__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj,value); + return; + } + super.__set__(obj,value); + } + + public void __delete__(PyObject obj) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__delete__"); + if (impl!=null) { + impl.__get__(this,self_type).__call__(obj); + return; + } + super.__delete__(obj); + } + + public PyObject __pow__(PyObject other,PyObject modulo) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__pow__"); + if (impl!=null) { + PyObject res; + if (modulo==null) { + res=impl.__get__(this,self_type).__call__(other); + } else { + res=impl.__get__(this,self_type).__call__(other,modulo); + } + if (res==Py.NotImplemented) + return null; + return res; + } + return super.__pow__(other,modulo); + } + + public void dispatch__init__(PyObject[]args,String[]keywords) { + Deriveds.dispatch__init__(this,args,keywords); + } + + public PyObject __index__() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__index__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (res instanceof PyInteger||res instanceof PyLong) { + return res; + } + throw Py.TypeError(String.format("__index__ returned non-(int,long) (type %s)",res.getType().fastGetName())); + } + return super.__index__(); + } + + public Object __tojava__(Class c) { + // If we are not being asked by the "default" conversion to java, then + // we can provide this as the result, as long as it is a instance of the + // specified class. Without this, derived.__tojava__(PyObject.class) + // would broke. (And that's not pure speculation: PyReflectedFunction's + // ReflectedArgs asks for things like that). + if ((c!=Object.class)&&(c!=Serializable.class)&&(c.isInstance(this))) { + return this; + } + // Otherwise, we call the derived __tojava__, if it exists: + PyType self_type=getType(); + PyObject impl=self_type.lookup("__tojava__"); + if (impl!=null) { + PyObject delegate=impl.__get__(this,self_type).__call__(Py.java2py(c)); + if (delegate!=this) + return delegate.__tojava__(Object.class); + } + return super.__tojava__(c); + } + + public Object __coerce_ex__(PyObject o) { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__coerce__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(o); + if (res==Py.NotImplemented) + return Py.None; + if (!(res instanceof PyTuple)) + throw Py.TypeError("__coerce__ didn't return a 2-tuple"); + return((PyTuple)res).getArray(); + } + return super.__coerce_ex__(o); + } + + public String toString() { + PyType self_type=getType(); + PyObject impl=self_type.lookup("__repr__"); + if (impl!=null) { + PyObject res=impl.__get__(this,self_type).__call__(); + if (!(res instanceof PyString)) + throw Py.TypeError("__repr__ returned non-string (type "+res.getType().fastGetName()+")"); + return((PyString)res).toString(); + } + return super.toString(); + } + +} diff --git a/src/org/python/modules/itertools/isliceDerived.java b/src/org/python/modules/itertools/isliceDerived.java index bba2164a5..cbed9c017 100644 --- a/src/org/python/modules/itertools/isliceDerived.java +++ b/src/org/python/modules/itertools/isliceDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/izipDerived.java b/src/org/python/modules/itertools/izipDerived.java index 32890bb5c..95c5c306f 100644 --- a/src/org/python/modules/itertools/izipDerived.java +++ b/src/org/python/modules/itertools/izipDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/izipLongestDerived.java b/src/org/python/modules/itertools/izipLongestDerived.java index bc12b3c6a..2821a85b6 100644 --- a/src/org/python/modules/itertools/izipLongestDerived.java +++ b/src/org/python/modules/itertools/izipLongestDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/permutationsDerived.java b/src/org/python/modules/itertools/permutationsDerived.java index 4b6b7101f..c0f4ca9dc 100644 --- a/src/org/python/modules/itertools/permutationsDerived.java +++ b/src/org/python/modules/itertools/permutationsDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/productDerived.java b/src/org/python/modules/itertools/productDerived.java index 732cbf8ff..aae3b75e4 100644 --- a/src/org/python/modules/itertools/productDerived.java +++ b/src/org/python/modules/itertools/productDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/repeatDerived.java b/src/org/python/modules/itertools/repeatDerived.java index ebe1cfd6d..99f2a9aaf 100644 --- a/src/org/python/modules/itertools/repeatDerived.java +++ b/src/org/python/modules/itertools/repeatDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/starmapDerived.java b/src/org/python/modules/itertools/starmapDerived.java index fadc1287f..13209bc3d 100644 --- a/src/org/python/modules/itertools/starmapDerived.java +++ b/src/org/python/modules/itertools/starmapDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/itertools/takewhileDerived.java b/src/org/python/modules/itertools/takewhileDerived.java index f3ceecce9..8447a4e03 100644 --- a/src/org/python/modules/itertools/takewhileDerived.java +++ b/src/org/python/modules/itertools/takewhileDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/jffi/AbstractMemoryCData.java b/src/org/python/modules/jffi/AbstractMemoryCData.java index 016e1226b..34b50c2c8 100644 --- a/src/org/python/modules/jffi/AbstractMemoryCData.java +++ b/src/org/python/modules/jffi/AbstractMemoryCData.java @@ -10,6 +10,7 @@ public abstract class AbstractMemoryCData extends CData implements Pointer { super(subtype, type); this.memory = memory; } + @Override public boolean __nonzero__() { return !getMemory().isNull(); diff --git a/src/org/python/modules/jffi/CType.java b/src/org/python/modules/jffi/CType.java index 871e0fc1f..49dc4444c 100644 --- a/src/org/python/modules/jffi/CType.java +++ b/src/org/python/modules/jffi/CType.java @@ -8,6 +8,8 @@ import org.python.core.PyObject; import org.python.core.PyType; import org.python.core.Untraversable; +import org.python.core.Traverseproc; +import org.python.core.Visitproc; import org.python.expose.ExposeAsSuperclass; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; @@ -98,6 +100,7 @@ final com.kenai.jffi.Type jffiType() { } } + @Untraversable @ExposedType(name = "jffi.Type.Custom", base = CType.class) static class Custom extends CType { final com.kenai.jffi.Type jffiType; @@ -127,7 +130,7 @@ static CType typeOf(PyObject obj) { } @ExposedType(name = "jffi.Type.Array", base = CType.class) - static final class Array extends CType.Custom { + static final class Array extends CType.Custom implements Traverseproc { public static final PyType TYPE = PyType.fromClass(Array.class); final CType componentType; final PyType pyComponentType; @@ -178,16 +181,33 @@ static final MemoryOp getComponentMemoryOp(PyType pyComponentType, CType compone throw Py.TypeError("only scalar and struct types supported"); } } + + + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + if (componentType != null) { + int res = visit.visit(componentType, arg); + if (res != 0) { + return res; + } + } + return pyComponentType != null ? visit.visit(pyComponentType, arg) : 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + return ob != null && (ob == componentType || ob == pyComponentType); + } } - @ExposedType(name = "jffi.Type.Pointer", base = CType.class) - final static class Pointer extends Custom { + final static class Pointer extends Custom implements Traverseproc { public static final PyType TYPE = PyType.fromClass(Pointer.class); private static final ConcurrentMap typeCache = new ConcurrentHashMap(); - + final CType componentType; final PyType pyComponentType; final MemoryOp componentMemoryOp; @@ -234,7 +254,7 @@ public static PyObject Pointer_new(PyNewWrapper new_, boolean init, PyType subty public final String toString() { return String.format("", componentType.toString()); } - + private static final class ScalarOp extends MemoryOp { private final MemoryOp op; private final PyType type; @@ -262,5 +282,21 @@ public final PyObject get(Memory mem, long offset) { } + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + if (componentType != null) { + int res = visit.visit(componentType, arg); + if (res != 0) { + return res; + } + } + return pyComponentType != null ? visit.visit(pyComponentType, arg) : 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + return ob != null && (ob == componentType || ob == pyComponentType); + } } } diff --git a/src/org/python/modules/jffi/DynamicLibrary.java b/src/org/python/modules/jffi/DynamicLibrary.java index 5c2fa28cf..f3d58feb9 100644 --- a/src/org/python/modules/jffi/DynamicLibrary.java +++ b/src/org/python/modules/jffi/DynamicLibrary.java @@ -57,6 +57,7 @@ public final PyObject find_variable(PyObject name) { return new DataSymbol(this, name.asString(), findSymbol(name)); } + @Untraversable @ExposedType(name = "jffi.DynamicLibrary.Symbol", base = PyObject.class) public static class Symbol extends BasePointer { public static final PyType TYPE = PyType.fromClass(Symbol.class); @@ -78,13 +79,15 @@ public final DirectMemory getMemory() { return memory; } } - + + @Untraversable public static final class TextSymbol extends Symbol implements ExposeAsSuperclass { public TextSymbol(DynamicLibrary lib, String name, long address) { super(lib, name, new SymbolMemory(lib, address)); } } + @Untraversable public static final class DataSymbol extends Symbol implements ExposeAsSuperclass { public DataSymbol(DynamicLibrary lib, String name, long address) { super(lib, name, new SymbolMemory(lib, address)); diff --git a/src/org/python/modules/jffi/Function.java b/src/org/python/modules/jffi/Function.java index 7b273c9a4..bc2662d8f 100644 --- a/src/org/python/modules/jffi/Function.java +++ b/src/org/python/modules/jffi/Function.java @@ -9,13 +9,15 @@ import org.python.core.PySequenceList; import org.python.core.PyStringMap; import org.python.core.PyType; +import org.python.core.Traverseproc; +import org.python.core.Visitproc; import org.python.expose.ExposedGet; import org.python.expose.ExposedNew; import org.python.expose.ExposedSet; import org.python.expose.ExposedType; @ExposedType(name = "jffi.Function", base = PyObject.class) -public class Function extends BasePointer implements Pointer { +public class Function extends BasePointer implements Traverseproc { public static final PyType TYPE = PyType.fromClass(Function.class); private final Pointer pointer; @@ -262,4 +264,54 @@ public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg return errcheck.__call__(invoker.invoke(arg1, arg2, arg3, arg4, arg5, arg6)); } } + + + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + int res = 0; + if (pointer != null && pointer instanceof PyObject) { + res = visit.visit((PyObject) pointer, arg); + if (res != 0) { + return res; + } + } + if (dict != null) { + res = visit.visit(dict, arg); + if (res != 0) { + return res; + } + } + if (restype != null) { + res = visit.visit(restype, arg); + if (res != 0) { + return res; + } + } + if (argtypes != null) { + for (PyObject obj: argtypes) { + res = visit.visit(obj, arg); + if (res != 0) { + return res; + } + } + } + return 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) throws UnsupportedOperationException { + if (ob != null && (pointer == ob || dict == ob || restype == ob)) { + return true; + }; + if (argtypes != null) + { + for (PyObject obj: argtypes) { + if (obj == ob) { + return true; + } + } + } + return false; + } } diff --git a/src/org/python/modules/jffi/JITInvoker.java b/src/org/python/modules/jffi/JITInvoker.java index 8e8869fb3..61967892d 100644 --- a/src/org/python/modules/jffi/JITInvoker.java +++ b/src/org/python/modules/jffi/JITInvoker.java @@ -1,12 +1,8 @@ package org.python.modules.jffi; -import com.kenai.jffi.*; import org.python.core.Py; import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker extends Invoker { protected static final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); protected final com.kenai.jffi.Function jffiFunction; diff --git a/src/org/python/modules/jffi/JITInvoker0.java b/src/org/python/modules/jffi/JITInvoker0.java index 3cc96458c..1f9ae8449 100644 --- a/src/org/python/modules/jffi/JITInvoker0.java +++ b/src/org/python/modules/jffi/JITInvoker0.java @@ -1,11 +1,7 @@ package org.python.modules.jffi; -import com.kenai.jffi.*; import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker0 extends JITInvoker { public JITInvoker0(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(0, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker1.java b/src/org/python/modules/jffi/JITInvoker1.java index fff4265dd..f0bea2394 100644 --- a/src/org/python/modules/jffi/JITInvoker1.java +++ b/src/org/python/modules/jffi/JITInvoker1.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker1 extends JITInvoker { public JITInvoker1(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(1, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker2.java b/src/org/python/modules/jffi/JITInvoker2.java index 74e07948e..5a72253d3 100644 --- a/src/org/python/modules/jffi/JITInvoker2.java +++ b/src/org/python/modules/jffi/JITInvoker2.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker2 extends JITInvoker { public JITInvoker2(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(2, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker3.java b/src/org/python/modules/jffi/JITInvoker3.java index a6cd82a8a..5652dbf14 100644 --- a/src/org/python/modules/jffi/JITInvoker3.java +++ b/src/org/python/modules/jffi/JITInvoker3.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker3 extends JITInvoker { public JITInvoker3(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(3, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker4.java b/src/org/python/modules/jffi/JITInvoker4.java index 10e95d29a..760c269ad 100644 --- a/src/org/python/modules/jffi/JITInvoker4.java +++ b/src/org/python/modules/jffi/JITInvoker4.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker4 extends JITInvoker { public JITInvoker4(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(4, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker5.java b/src/org/python/modules/jffi/JITInvoker5.java index d9d7238a4..e1b5da1fd 100644 --- a/src/org/python/modules/jffi/JITInvoker5.java +++ b/src/org/python/modules/jffi/JITInvoker5.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker5 extends JITInvoker { public JITInvoker5(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(5, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITInvoker6.java b/src/org/python/modules/jffi/JITInvoker6.java index d472df404..66dd01988 100644 --- a/src/org/python/modules/jffi/JITInvoker6.java +++ b/src/org/python/modules/jffi/JITInvoker6.java @@ -2,9 +2,6 @@ import org.python.core.PyObject; -/** - * - */ abstract public class JITInvoker6 extends JITInvoker { public JITInvoker6(com.kenai.jffi.Function function, Invoker fallbackInvoker) { super(6, function, fallbackInvoker); diff --git a/src/org/python/modules/jffi/JITMethodGenerator.java b/src/org/python/modules/jffi/JITMethodGenerator.java index f4b83d180..44a1749cd 100644 --- a/src/org/python/modules/jffi/JITMethodGenerator.java +++ b/src/org/python/modules/jffi/JITMethodGenerator.java @@ -1,8 +1,5 @@ package org.python.modules.jffi; -/** - * - */ public interface JITMethodGenerator { public boolean isSupported(JITSignature signature); diff --git a/src/org/python/modules/jffi/JITRuntime.java b/src/org/python/modules/jffi/JITRuntime.java index fe88a89c2..72652323a 100644 --- a/src/org/python/modules/jffi/JITRuntime.java +++ b/src/org/python/modules/jffi/JITRuntime.java @@ -5,9 +5,6 @@ import java.math.BigInteger; -/** - * - */ public final class JITRuntime { private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); diff --git a/src/org/python/modules/jffi/JITSignature.java b/src/org/python/modules/jffi/JITSignature.java index 35b72a8a1..73a60f637 100644 --- a/src/org/python/modules/jffi/JITSignature.java +++ b/src/org/python/modules/jffi/JITSignature.java @@ -1,12 +1,8 @@ package org.python.modules.jffi; import com.kenai.jffi.CallingConvention; - import java.util.Arrays; -/** - * - */ public final class JITSignature { private final NativeType resultType; private final NativeType[] parameterTypes; diff --git a/src/org/python/modules/jffi/Memory.java b/src/org/python/modules/jffi/Memory.java index b71a4d3dc..8ea0b3101 100644 --- a/src/org/python/modules/jffi/Memory.java +++ b/src/org/python/modules/jffi/Memory.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; /** diff --git a/src/org/python/modules/jffi/MemoryOp.java b/src/org/python/modules/jffi/MemoryOp.java index 176725225..a5efdbaf8 100644 --- a/src/org/python/modules/jffi/MemoryOp.java +++ b/src/org/python/modules/jffi/MemoryOp.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import org.python.core.Py; diff --git a/src/org/python/modules/jffi/NativeDataConverter.java b/src/org/python/modules/jffi/NativeDataConverter.java index e2d8f8df8..1c7624e74 100644 --- a/src/org/python/modules/jffi/NativeDataConverter.java +++ b/src/org/python/modules/jffi/NativeDataConverter.java @@ -1,11 +1,7 @@ package org.python.modules.jffi; - import org.python.core.PyObject; -/** - * - */ abstract public class NativeDataConverter { private final boolean referenceRequired; private final boolean postInvokeRequired; diff --git a/src/org/python/modules/jffi/NativeMemory.java b/src/org/python/modules/jffi/NativeMemory.java index 22cdd0b0b..842767404 100644 --- a/src/org/python/modules/jffi/NativeMemory.java +++ b/src/org/python/modules/jffi/NativeMemory.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import com.kenai.jffi.Platform; diff --git a/src/org/python/modules/jffi/NativeType.java b/src/org/python/modules/jffi/NativeType.java index a052ec130..ae72e2cc2 100644 --- a/src/org/python/modules/jffi/NativeType.java +++ b/src/org/python/modules/jffi/NativeType.java @@ -1,7 +1,5 @@ - package org.python.modules.jffi; - public enum NativeType { VOID, BOOL, diff --git a/src/org/python/modules/jffi/NullMemory.java b/src/org/python/modules/jffi/NullMemory.java index bedeef9bd..74dd7f6a2 100644 --- a/src/org/python/modules/jffi/NullMemory.java +++ b/src/org/python/modules/jffi/NullMemory.java @@ -1,5 +1,3 @@ - - package org.python.modules.jffi; /** diff --git a/src/org/python/modules/jffi/Pointer.java b/src/org/python/modules/jffi/Pointer.java index 211d7790c..b3a914f44 100644 --- a/src/org/python/modules/jffi/Pointer.java +++ b/src/org/python/modules/jffi/Pointer.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; public interface Pointer { diff --git a/src/org/python/modules/jffi/PointerCData.java b/src/org/python/modules/jffi/PointerCData.java index a6972353c..4037891a6 100644 --- a/src/org/python/modules/jffi/PointerCData.java +++ b/src/org/python/modules/jffi/PointerCData.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import org.python.core.Py; diff --git a/src/org/python/modules/jffi/ScalarCData.java b/src/org/python/modules/jffi/ScalarCData.java index 85e53f931..a423967de 100644 --- a/src/org/python/modules/jffi/ScalarCData.java +++ b/src/org/python/modules/jffi/ScalarCData.java @@ -1,14 +1,11 @@ - package org.python.modules.jffi; import org.python.core.Py; import org.python.core.PyFloat; -import org.python.core.PyInteger; -import org.python.core.PyLong; import org.python.core.PyNewWrapper; import org.python.core.PyObject; -import org.python.core.PyObject.ConversionException; import org.python.core.PyType; +import org.python.core.Visitproc; import org.python.expose.ExposedClassMethod; import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; @@ -19,9 +16,9 @@ @ExposedType(name = "jffi.ScalarCData", base = CData.class) public class ScalarCData extends CData { public static final PyType TYPE = PyType.fromClass(ScalarCData.class); - static { +// static { // TYPE.fastGetDict().__setitem__("in_dll", new InDll()); - } +// } private PyObject value; @ExposedNew @@ -121,4 +118,25 @@ public PyFloat __float__() { public final String toString() { return getType().getName() + "(" + getValue().toString() + ")"; } + + + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + if (value != null) { + int res = visit.visit(value, arg); + if (res != 0) { + return res; + } + } + return super.traverse(visit, arg); + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + if (ob != null && ob == value) { + return true; + } + return super.refersDirectlyTo(ob); + } } diff --git a/src/org/python/modules/jffi/SkinnyMethodAdapter.java b/src/org/python/modules/jffi/SkinnyMethodAdapter.java index 6173399cd..c098c515b 100644 --- a/src/org/python/modules/jffi/SkinnyMethodAdapter.java +++ b/src/org/python/modules/jffi/SkinnyMethodAdapter.java @@ -31,7 +31,7 @@ public class SkinnyMethodAdapter extends MethodVisitor implements Opcodes { private ClassVisitor cv; public SkinnyMethodAdapter(ClassVisitor cv, int flags, String name, String signature, String something, String[] exceptions) { - super(ASM4); + super(ASM7); setMethodVisitor(cv.visitMethod(flags, name, signature, something, exceptions)); this.cv = cv; this.name = name; @@ -153,19 +153,19 @@ public void pushBoolean(boolean bool) { } public void invokestatic(String arg1, String arg2, String arg3) { - getMethodVisitor().visitMethodInsn(INVOKESTATIC, arg1, arg2, arg3); + getMethodVisitor().visitMethodInsn(INVOKESTATIC, arg1, arg2, arg3, false); } public void invokespecial(String arg1, String arg2, String arg3) { - getMethodVisitor().visitMethodInsn(INVOKESPECIAL, arg1, arg2, arg3); + getMethodVisitor().visitMethodInsn(INVOKESPECIAL, arg1, arg2, arg3, false); } public void invokevirtual(String arg1, String arg2, String arg3) { - getMethodVisitor().visitMethodInsn(INVOKEVIRTUAL, arg1, arg2, arg3); + getMethodVisitor().visitMethodInsn(INVOKEVIRTUAL, arg1, arg2, arg3, false); } public void invokeinterface(String arg1, String arg2, String arg3) { - getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, arg1, arg2, arg3); + getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, arg1, arg2, arg3, true); } public void aprintln() { @@ -840,8 +840,13 @@ public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) { getMethodVisitor().visitFieldInsn(arg0, arg1, arg2, arg3); } + @Deprecated public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) { - getMethodVisitor().visitMethodInsn(arg0, arg1, arg2, arg3); + getMethodVisitor().visitMethodInsn(arg0, arg1, arg2, arg3, arg0 == Opcodes.INVOKEINTERFACE); + } + + public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3, boolean arg4) { + getMethodVisitor().visitMethodInsn(arg0, arg1, arg2, arg3, arg4); } public void visitJumpInsn(int arg0, Label arg1) { diff --git a/src/org/python/modules/jffi/StringCData.java b/src/org/python/modules/jffi/StringCData.java index 9d31a471a..07f68b6d1 100644 --- a/src/org/python/modules/jffi/StringCData.java +++ b/src/org/python/modules/jffi/StringCData.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import org.python.core.Py; @@ -52,7 +51,6 @@ public PyObject getValue() { : Py.None; } - @ExposedSet(name = "value") public void setValue(PyObject value) { byte[] str = value.asString().getBytes(); @@ -76,6 +74,4 @@ public String asString() { ? new String(m.getZeroTerminatedByteArray(0)) : null; } - - } diff --git a/src/org/python/modules/jffi/StructLayout.java b/src/org/python/modules/jffi/StructLayout.java index d275b13b3..bffbe5e36 100644 --- a/src/org/python/modules/jffi/StructLayout.java +++ b/src/org/python/modules/jffi/StructLayout.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import java.util.Arrays; @@ -20,7 +19,7 @@ import org.python.expose.ExposedType; @ExposedType(name = "jffi.StructLayout", base = CType.class) -public class StructLayout extends CType.Custom { +public class StructLayout extends CType.Custom implements Traverseproc { public static final PyType TYPE = PyType.fromClass(StructLayout.class); static { TYPE.fastGetDict().__setitem__("Field", Field.TYPE); @@ -141,8 +140,8 @@ public static final StructLayout newStructLayout(Field[] fields, boolean isUnion } com.kenai.jffi.Type jffiType = isUnion - ? new com.kenai.jffi.Union(fieldTypes) - : new com.kenai.jffi.Struct(fieldTypes); + ? com.kenai.jffi.Union.newUnion(fieldTypes) + : com.kenai.jffi.Struct.newStruct(fieldTypes); return new StructLayout(fields, jffiType, MemoryOp.INVALID); } @@ -207,4 +206,44 @@ public PyObject __getitem__(PyObject key) { StructLayout.Field f = getField(key); return f != null ? f : Py.None; } + + + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + int res = 0; + if (fields != null) { + for (Field fld: fields) { + res = visit.visit(fld, arg); + if (res != 0) { + return res; + } + } + } + if (fieldMap != null) { + for (Object key: fieldMap.keySet()) { + if (key instanceof PyObject) { + res = visit.visit((PyObject) key, arg); + if (res != 0) { + return res; + } + } + } + } + return 0; + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + if (ob == null) { + return false; + } + if (fields != null && fields.contains(ob)) { + return true; + } + if (fieldMap != null && fieldMap.containsKey(ob)) { + return true; + } + return false; + } } diff --git a/src/org/python/modules/jffi/Structure.java b/src/org/python/modules/jffi/Structure.java index 9835ee13c..bc4a4f08c 100644 --- a/src/org/python/modules/jffi/Structure.java +++ b/src/org/python/modules/jffi/Structure.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import java.util.List; @@ -6,12 +5,14 @@ import org.python.core.PyNewWrapper; import org.python.core.PyObject; import org.python.core.PyType; +import org.python.core.Traverseproc; +import org.python.core.Visitproc; import org.python.expose.ExposedClassMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; @ExposedType(name = "jffi.Structure", base = CData.class) -public class Structure extends CData implements Pointer { +public class Structure extends CData implements Pointer, Traverseproc { public static final PyType TYPE = PyType.fromClass(Structure.class); private final StructLayout layout; @@ -100,4 +101,23 @@ public DirectMemory getMemory() { return getReferenceMemory(); } + /* Traverseproc implementation */ + @Override + public int traverse(Visitproc visit, Object arg) { + if (layout != null) { + int res = visit.visit(layout, arg); + if (res != 0) { + return res; + } + } + return super.traverse(visit, arg); + } + + @Override + public boolean refersDirectlyTo(PyObject ob) { + if (ob != null && layout == ob) { + return true; + } + return super.refersDirectlyTo(ob); + } } diff --git a/src/org/python/modules/jffi/Util.java b/src/org/python/modules/jffi/Util.java index 06cd57568..edc85e410 100644 --- a/src/org/python/modules/jffi/Util.java +++ b/src/org/python/modules/jffi/Util.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import java.math.BigInteger; diff --git a/src/org/python/modules/jffi/jffi.java b/src/org/python/modules/jffi/jffi.java index 17a31506d..5bbf7094b 100644 --- a/src/org/python/modules/jffi/jffi.java +++ b/src/org/python/modules/jffi/jffi.java @@ -1,4 +1,3 @@ - package org.python.modules.jffi; import com.kenai.jffi.Library; diff --git a/src/org/python/modules/math.java b/src/org/python/modules/math.java index 87f15f2aa..1d75067d0 100644 --- a/src/org/python/modules/math.java +++ b/src/org/python/modules/math.java @@ -544,7 +544,7 @@ static PyException mathRangeError() { * @param arg to include in check * @return result if arg was NaN or result was not * NaN - * @throws PyException (ValueError) if result was NaN and + * @throws PyException {@code ValueError} if result was NaN and * arg was not NaN */ private static double exceptNaN(double result, double arg) throws PyException { @@ -570,8 +570,8 @@ private static double exceptNaN(double result, double arg) throws PyException { * @param result to return (if we return) * @param arg to include in check * @return result if arg was infinite or result was not infinite - * @throws PyException (ValueError) if result was infinite and arg was - * not infinite + * @throws PyException {@code ValueError} if result was infinite and + * arg was not infinite */ private static double exceptInf(double result, double arg) { if (Double.isInfinite(result) && !Double.isInfinite(arg)) { diff --git a/src/org/python/modules/posix/Hider.java b/src/org/python/modules/posix/Hider.java index d816cf694..f0e2d3c2c 100644 --- a/src/org/python/modules/posix/Hider.java +++ b/src/org/python/modules/posix/Hider.java @@ -50,27 +50,24 @@ private static boolean isHidden(Method method, OS os, PosixImpl posixImpl) { } return false; } -} -/** - * Tags PosixModule methods as hidden on the specified OS or PosixImpl. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@interface Hide { + /** Tags PosixModule methods as hidden on the specified OS or PosixImpl. */ + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.METHOD) + @interface Hide { - /** Hide method on these OSes. */ - OS[] value() default {}; + /** Hide method on these OSes. */ + OS[] value() default {}; - /** - * @Hide(posixImpl = PosixImpl.JAVA) hides the method from Python when the POSIX - * library isn't native. The default NOT_APPLICABLE means the POSIX implementation - * doesn't matter. - */ - PosixImpl posixImpl() default PosixImpl.NOT_APPLICABLE; -} + /** + * @Hide(posixImpl = PosixImpl.JAVA) hides the method from Python when the POSIX + * library isn't native. The default NOT_APPLICABLE means the POSIX implementation + * doesn't matter. + */ + PosixImpl posixImpl() default PosixImpl.NOT_APPLICABLE; + } -/** - * The type of underlying POSIX library implementation (native or not). - */ -enum PosixImpl {NOT_APPLICABLE, NATIVE, JAVA}; + /** The type of underlying POSIX library implementation (native or not). */ + enum PosixImpl {NOT_APPLICABLE, NATIVE, JAVA}; + +} diff --git a/src/org/python/modules/posix/OS.java b/src/org/python/modules/posix/OS.java index 56fa512d0..ede79c7e9 100644 --- a/src/org/python/modules/posix/OS.java +++ b/src/org/python/modules/posix/OS.java @@ -3,6 +3,7 @@ import java.util.Locale; import org.python.core.PySystemState; +import org.python.core.RegistryKey; /** * A Marker tagging what OS we're running on, with some accompanying information about @@ -44,7 +45,8 @@ String[][] getShellCommands() { * Return the OS we're running on. */ static OS getOS() { - String osName = PySystemState.registry.getProperty("python.os"); + String osName = PySystemState.registry.getProperty( + RegistryKey.PYTHON_OS); if (osName == null) { osName = System.getProperty("os.name"); } diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java index 0bce7761a..e3a8dd9e6 100644 --- a/src/org/python/modules/posix/PosixModule.java +++ b/src/org/python/modules/posix/PosixModule.java @@ -57,6 +57,7 @@ import org.python.core.PyString; import org.python.core.PySystemState; import org.python.core.PyTuple; +import org.python.core.PyUnicode; import org.python.core.Untraversable; import org.python.core.imp; import org.python.core.io.FileIO; @@ -342,7 +343,7 @@ public static void chmod(PyObject path, int mode) { public static PyString __doc__chown = new PyString( "chown(path, uid, gid)\n\n" + "Change the owner and group id of path to the numeric uid and gid."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static void chown(PyObject path, int uid, int gid) { if (posix.chown(absolutePath(path).toString(), uid, gid) < 0) { throw errorFromErrno(path); @@ -361,7 +362,7 @@ public static void close(PyObject fd) { } } - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static void closerange(PyObject fd_lowObj, PyObject fd_highObj) { int fd_low = getFD(fd_lowObj).getIntFD(false); int fd_high = getFD(fd_highObj).getIntFD(false); @@ -423,7 +424,7 @@ public static PyObject fdopen(PyObject fd, String mode, int bufsize) { "fdatasync(fildes)\n\n" + "force write of file with filedescriptor to disk.\n" + "does not force update of metadata."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static void fdatasync(PyObject fd) { Object javaobj = fd.__tojava__(RawIOBase.class); if (javaobj != Py.NoConversion) { @@ -486,7 +487,8 @@ public static void ftruncate(PyObject fd, long length) { "getcwd() -> path\n\n" + "Return a string representing the current working directory."); public static PyObject getcwd() { - return Py.newStringOrUnicode(Py.getSystemState().getCurrentWorkingDir()); + // The return value is bytes in the file system encoding + return Py.fileSystemEncode(Py.getSystemState().getCurrentWorkingDir()); } public static PyString __doc__getcwdu = new PyString( @@ -499,7 +501,7 @@ public static PyObject getcwdu() { public static PyString __doc__getegid = new PyString( "getegid() -> egid\n\n" + "Return the current process's effective group id."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static int getegid() { return posix.getegid(); } @@ -507,7 +509,7 @@ public static int getegid() { public static PyString __doc__geteuid = new PyString( "geteuid() -> euid\n\n" + "Return the current process's effective user id."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static int geteuid() { return posix.geteuid(); } @@ -515,7 +517,7 @@ public static int geteuid() { public static PyString __doc__getgid = new PyString( "getgid() -> gid\n\n" + "Return the current process's group id."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static int getgid() { return posix.getgid(); } @@ -523,15 +525,21 @@ public static int getgid() { public static PyString __doc__getlogin = new PyString( "getlogin() -> string\n\n" + "Return the actual login name."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static PyObject getlogin() { - return new PyString(posix.getlogin()); + String login = posix.getlogin(); + if (login == null) { + // recommend according to https://docs.python.org/2/library/os.html#os.getlogin + throw Py.OSError( + "getlogin OS call failed. Preferentially use os.getenv('LOGNAME') instead."); + } + return new PyString(login); } public static PyString __doc__getppid = new PyString( "getppid() -> ppid\n\n" + "Return the parent's process id."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static int getppid() { return posix.getppid(); } @@ -539,7 +547,7 @@ public static int getppid() { public static PyString __doc__getuid = new PyString( "getuid() -> uid\n\n" + "Return the current process's user id."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static int getuid() { return posix.getuid(); } @@ -548,7 +556,7 @@ public static int getuid() { "getpid() -> pid\n\n" + "Return the current process id"); - @Hide(posixImpl = PosixImpl.JAVA) + @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA) public static int getpid() { return posix.getpid(); } @@ -556,7 +564,7 @@ public static int getpid() { public static PyString __doc__getpgrp = new PyString( "getpgrp() -> pgrp\n\n" + "Return the current process group id."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static int getpgrp() { return posix.getpgrp(); } @@ -567,7 +575,7 @@ public static int getpgrp() { "isatty(fd) -> bool\n\n" + "Return True if the file descriptor 'fd' is an open file descriptor\n" + "connected to the slave end of a terminal."); - @Hide(posixImpl = PosixImpl.JAVA) + @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA) public static boolean isatty(PyObject fdObj) { Object tojava = fdObj.__tojava__(IOBase.class); if (tojava != Py.NoConversion) { @@ -601,7 +609,7 @@ public static boolean isatty(PyObject fdObj) { public static PyString __doc__kill = new PyString( "kill(pid, sig)\n\n" + "Kill a process with a signal."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static void kill(int pid, int sig) { if (posix.kill(pid, sig) < 0) { throw errorFromErrno(); @@ -612,7 +620,7 @@ public static void kill(int pid, int sig) { "lchmod(path, mode)\n\n" + "Change the access permissions of a file. If path is a symlink, this\n" + "affects the link itself rather than the target."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static void lchmod(PyObject path, int mode) { if (posix.lchmod(absolutePath(path).toString(), mode) < 0) { throw errorFromErrno(path); @@ -623,7 +631,7 @@ public static void lchmod(PyObject path, int mode) { "lchown(path, uid, gid)\n\n" + "Change the owner and group id of path to the numeric uid and gid.\n" + "This function will not follow symbolic links."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static void lchown(PyObject path, int uid, int gid) { if (posix.lchown(absolutePath(path).toString(), uid, gid) < 0) { throw errorFromErrno(path); @@ -634,7 +642,7 @@ public static void lchown(PyObject path, int uid, int gid) { "link(src, dst)\n\n" + "Create a hard link to a file."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static void link(PyObject src, PyObject dst) { try { Files.createLink(Paths.get(asPath(dst)), Paths.get(asPath(src))); @@ -670,9 +678,16 @@ public static PyList listdir(PyObject path) { throw Py.OSError("listdir(): an unknown error occurred: " + path); } + // Return names as bytes or unicode according to the type of the original argument PyList list = new PyList(); - for (String name : names) { - list.append(Py.newStringOrUnicode(path, name)); + if (path instanceof PyUnicode) { + for (String name : names) { + list.append(Py.newUnicode(name)); + } + } else { + for (String name : names) { + list.append(Py.fileSystemEncode(name)); + } } return list; } @@ -842,7 +857,7 @@ public static PyObject read(PyObject fd, int buffersize) { public static PyString __doc__readlink = new PyString( "readlink(path) -> path\n\n" + "Return a string representing the path to which the symbolic link points."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static PyString readlink(PyObject path) { try { return Py.newStringOrUnicode(path, Files.readSymbolicLink(absolutePath(path)).toString()); @@ -893,7 +908,7 @@ public static void rmdir(PyObject path) { public static PyString __doc__setpgrp = new PyString( "setpgrp()\n\n" + "Make this process a session leader."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static void setpgrp() { if (posix.setpgrp(0, 0) < 0) { throw errorFromErrno(); @@ -903,7 +918,7 @@ public static void setpgrp() { public static PyString __doc__setsid = new PyString( "setsid()\n\n" + "Call the system call setsid()."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static void setsid() { if (posix.setsid() < 0) { throw errorFromErrno(); @@ -931,7 +946,7 @@ public static PyObject strerror(int code) { "symlink(src, dst)\n\n" + "Create a symbolic link pointing to src named dst."); - @Hide(OS.NT) + @Hider.Hide(OS.NT) public static void symlink(PyObject src, PyObject dst) { try { Files.createSymbolicLink(Paths.get(asPath(dst)), Paths.get(asPath(src))); @@ -952,7 +967,7 @@ private static PyFloat ratio(long num, long div) { "times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n" + "Return a tuple of floating point numbers indicating process times."); - @Hide(posixImpl = PosixImpl.JAVA) + @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA) public static PyTuple times() { Times times = posix.times(); long CLK_TCK = Sysconf._SC_CLK_TCK.longValue(); @@ -968,7 +983,7 @@ public static PyTuple times() { public static PyString __doc__umask = new PyString( "umask(new_mask) -> old_mask\n\n" + "Set the current numeric umask and return the previous umask."); - @Hide(posixImpl = PosixImpl.JAVA) + @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA) public static int umask(int mask) { return posix.umask(mask); } @@ -1027,172 +1042,69 @@ public static int umask(int mask) { * @return PyTuple containing sysname, nodename, release, version, machine */ public static PyTuple uname() { - if (uname_cache != null) { - return uname_cache; - } -// todo: Giving os.uname a windows-implementation might break platform.uname. Check this! - String sysname = System.getProperty("os.name"); - String sysrelease; - boolean win; - if (sysname.equals("Mac OS X")) { - sysname = "Darwin"; - win = false; - try { - Process p = Runtime.getRuntime().exec("uname -r"); - java.io.BufferedReader br = new java.io.BufferedReader( - new java.io.InputStreamReader(p.getInputStream())); - sysrelease = br.readLine(); - // to end the process sanely in case we deal with some - // implementation that emits additional new-lines: - while (br.readLine() != null) { - ; - } - br.close(); - if (p.waitFor() != 0) { - sysrelease = ""; - } - } catch (Exception e) { - sysrelease = ""; - } - } else { - win = sysname.startsWith("Windows"); - if (win) { - sysrelease = sysname.length() > 7 ? sysname.substring(8) : - System.getProperty("os.version"); + if (uname_cache == null) { + // First call: have to construct the result. + String sysname = System.getProperty("os.name"); + String sysrelease, nodename, machine; + boolean win = false; + + if (sysname.equals("Mac OS X")) { + sysname = "Darwin"; + sysrelease = Py.getCommandResult("uname", "-r"); + } else if (sysname.startsWith("Windows")) { + sysrelease = sysname.length() > 7 ? sysname.substring(8) + : System.getProperty("os.version", ""); sysname = "Windows"; + win = true; } else { - sysrelease = System.getProperty("os.version"); + sysrelease = System.getProperty("os.version", ""); } - } - String uname_nodename; - try { - uname_nodename = java.net.InetAddress.getLocalHost().getHostName(); - } catch (Exception e) { - // Do nothing to leverage fallback - uname_nodename = null; - } - if (uname_nodename == null && win) { - uname_nodename = System.getenv("USERDOMAIN"); - } - if (uname_nodename == null) { try { - Process p = Runtime.getRuntime().exec( - win ? "hostname" : "uname -n"); - java.io.BufferedReader br = new java.io.BufferedReader( - new java.io.InputStreamReader(p.getInputStream())); - uname_nodename = br.readLine(); - // to end the process sanely in case we deal with some - // implementation that emits additional new-lines: - while (br.readLine() != null) { - ; - } - br.close(); - if (p.waitFor() != 0) { - uname_nodename = ""; - } + nodename = java.net.InetAddress.getLocalHost().getHostName(); } catch (Exception e) { - uname_nodename = ""; - } - } - - String uname_sysver; - try { - Process p = Runtime.getRuntime().exec( - win ? "cmd.exe /C ver" : "uname -v"); - java.io.BufferedReader br = new java.io.BufferedReader( - new java.io.InputStreamReader(p.getInputStream())); - uname_sysver = br.readLine(); - while (uname_sysver != null && uname_sysver.length() == 0) { - uname_sysver = br.readLine(); - } - // to end the process sanely in case we deal with some - // implementation that emits additional new-lines: - while (br.readLine() != null) { - ; - } - br.close(); - if (p.waitFor() != 0) { - // No fallback for sysver available - uname_sysver = ""; - } - if (win && uname_sysver.length() > 0) { - int start = uname_sysver.toLowerCase().indexOf("version "); - if (start != -1) { - start += 8; - int end = uname_sysver.length(); - if (uname_sysver.endsWith("]")) { - --end; + // If that fails, try the shell. + if (win) { + nodename = Py.getenv("USERDOMAIN", ""); + if (nodename.isEmpty()) { + nodename = Py.getCommandResult("hostname"); } - uname_sysver = uname_sysver.substring(start, end); + } else { + nodename = Py.getCommandResult("uname", "-n"); } } - } catch (Exception e) { - uname_sysver = ""; - } - String uname_machine; - try { + String sysver = PySystemState.getSystemVersionString(); + if (win) { - String machine = System.getenv("PROCESSOR_ARCHITECTURE"); - if (machine.equals("x86")) { - // maybe 32-bit process running on 64 bit machine - machine = System.getenv("PROCESSOR_ARCHITEW6432"); + // Check if 32-bit process on a 64 bit machine (compare platform.py) + machine = Py.getenv("PROCESSOR_ARCHITEW6432", ""); + if (machine.isEmpty()) { + // Otherwise, this contains the value (or we default to null) + machine = Py.getenv("PROCESSOR_ARCHITECTURE", ""); } - // if machine == null it's actually a 32-bit machine - uname_machine = machine == null ? "x86" : machine; -// We refrain from this normalization in order to match platform.uname behavior on Windows: -/* if (machine == null) { - uname_machine = "i686"; - } else if (machine.equals("AMD64") || machine.equals("EM64T")) { - uname_machine = "x86_64"; - } else if (machine.equals("IA64")) { - uname_machine = "ia64"; - } else { - uname_machine = machine.toLowerCase(); - } */ } else { - Process p = Runtime.getRuntime().exec("uname -m"); - java.io.BufferedReader br = new java.io.BufferedReader( - new java.io.InputStreamReader(p.getInputStream())); - uname_machine = br.readLine(); - // to end the process sanely in case we deal with some - // implementation that emits additional new-lines: - while (br.readLine() != null) { - ; - } - br.close(); - if (p.waitFor() != 0) { - // To leverage os.arch-fallback: - uname_machine = null; - } + machine = Py.getCommandResult("uname", "-m"); } - } catch (Exception e) { - // To leverage os.arch-fallback: - uname_machine = null; - } - if (uname_machine == null) { - String machine = System.getProperty("os.arch"); - if (machine == null) { - uname_machine = ""; - } else if (machine.equals("amd64")) { - // Normalize the common amd64-case to x86_64: - uname_machine = "x86_64"; - } else if (machine.equals("x86")) { - uname_machine = "i686"; - } else { - uname_machine = machine; + + if (machine.isEmpty()) { + machine = System.getProperty("os.arch", ""); + if (machine.equals("amd64")) { + // 64-bit processor presents as x86_64 on Linux and AMD64 on Windows. + machine = win ? "AMD64" : "x86_64"; + } else if (machine.equals("x86")) { + machine = "i686"; + } } - } - PyObject[] vals = { - Py.newString(sysname), - Py.newString(uname_nodename), - Py.newString(sysrelease), - Py.newString(uname_sysver), - Py.newString(uname_machine) - }; - uname_cache = new PyTuple(vals, false); + uname_cache = new PyTuple(new PyObject[] { + Py.fileSystemEncode(sysname), + Py.fileSystemEncode(nodename), + Py.fileSystemEncode(sysrelease), + Py.fileSystemEncode(sysver), + Py.fileSystemEncode(machine)}, + false); + } return uname_cache; } @@ -1270,7 +1182,7 @@ private static FileTime getFileTime(PyObject seconds) { public static PyString __doc__wait = new PyString( "wait() -> (pid, status)\n\n" + "Wait for completion of a child process."); - @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA) + @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA) public static PyObject wait$() { int[] status = new int[1]; int pid = posix.wait(status); @@ -1283,7 +1195,7 @@ private static FileTime getFileTime(PyObject seconds) { public static PyString __doc__waitpid = new PyString( "wait() -> (pid, status)\n\n" + "Wait for completion of a child process."); - @Hide(posixImpl = PosixImpl.JAVA) + @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA) public static PyObject waitpid(int pid, int options) { int[] status = new int[1]; pid = posix.waitpid(pid, status, options); @@ -1296,9 +1208,9 @@ public static PyObject waitpid(int pid, int options) { public static PyString __doc__write = new PyString( "write(fd, string) -> byteswritten\n\n" + "Write a string to a file descriptor."); - public static int write(PyObject fd, BufferProtocol bytes) { - // Get a buffer view: we can cope with N-dimensional data, but not strided data. - try (PyBuffer buf = bytes.getBuffer(PyBUF.ND)) { + + public static int write(PyObject fd, PyObject bytes) { + try (PyBuffer buf = ((BufferProtocol) bytes).getBuffer(PyBUF.SIMPLE)) { // Get a ByteBuffer of that data, setting the position and limit to the real data. ByteBuffer bb = buf.getNIOByteBuffer(); Object javaobj = fd.__tojava__(RawIOBase.class); @@ -1311,6 +1223,9 @@ public static int write(PyObject fd, BufferProtocol bytes) { } else { return posix.write(getFD(fd).getIntFD(), bb, bb.position()); } + } catch (ClassCastException e) { + throw Py.TypeError( + "write() argument 2 must be string or buffer, not " + bytes.getType()); } } @@ -1371,25 +1286,24 @@ private static PyObject getEnviron() { return environ; } for (Map.Entry entry : env.entrySet()) { + // The shell restricts names to a subset of ASCII and values are encoded byte strings. environ.__setitem__( - Py.newStringOrUnicode(entry.getKey()), - Py.newStringOrUnicode(entry.getValue())); + Py.newString(entry.getKey()), + Py.fileSystemEncode(entry.getValue())); } return environ; } /** - * Return a path as a String from a PyObject + * Return a path as a String from a PyObject, which must be str or + * unicode. If the path is a str (that is, bytes), it is + * interpreted into Unicode using the file system encoding. * * @param path a PyObject, raising a TypeError if an invalid path type * @return a String path */ private static String asPath(PyObject path) { - if (path instanceof PyString) { - return path.toString(); - } - throw Py.TypeError(String.format("coercing to Unicode: need string, %s type found", - path.getType().fastGetName())); + return Py.fileSystemDecode(path); } /** diff --git a/src/org/python/modules/posix/PyStatResult.java b/src/org/python/modules/posix/PyStatResult.java index 313ae3f55..4c24118ff 100644 --- a/src/org/python/modules/posix/PyStatResult.java +++ b/src/org/python/modules/posix/PyStatResult.java @@ -42,7 +42,8 @@ public class PyStatResult extends PyTuple { public static final int n_sequence_fields = 10, n_fields = 10, n_unnamed_fields = 10; PyStatResult(PyObject... vals) { - super(TYPE, vals); + super(TYPE, new PyObject[] {vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], + vals[7].__int__(), vals[8].__int__(), vals[9].__int__()}); st_mode = vals[0]; st_ino = vals[1]; st_dev = vals[2]; @@ -55,6 +56,20 @@ public class PyStatResult extends PyTuple { st_ctime = vals[9]; } + protected PyStatResult(PyObject[] vals, PyObject st_atime, PyObject st_mtime, PyObject st_ctime) { + super(TYPE, vals); + st_mode = vals[0]; + st_ino = vals[1]; + st_dev = vals[2]; + st_nlink = vals[3]; + st_uid = vals[4]; + st_gid = vals[5]; + st_size = vals[6]; + this.st_atime = st_atime; + this.st_mtime = st_mtime; + this.st_ctime = st_ctime; + } + @ExposedNew static PyObject stat_result_new(PyNewWrapper wrapper, boolean init, PyType subtype, PyObject[] args, String[] keywords) { @@ -67,7 +82,12 @@ static PyObject stat_result_new(PyNewWrapper wrapper, boolean init, PyType subty throw Py.TypeError(msg); } // tuples are immutable, so we can just use its underlying array - return new PyStatResult(((PyTuple)obj).getArray()); + if (obj instanceof PyStatResult) { + return new PyStatResult(((PyTuple) obj).getArray(), ((PyStatResult) obj).st_atime, + ((PyStatResult) obj).st_mtime, ((PyStatResult) obj).st_ctime); + } else { + return new PyStatResult(((PyTuple) obj).getArray()); + } } else { PyList seq = new PyList(obj); @@ -101,7 +121,7 @@ private static double fromFileTime(FileTime fileTime) { private static Long zeroOrValue(Long value) { if (value == null) { - return new Long(0L); + return Long.valueOf(0L); } else { return value; } @@ -109,7 +129,7 @@ private static Long zeroOrValue(Long value) { private static Integer zeroOrValue(Integer value) { if (value == null) { - return new Integer(0); + return Integer.valueOf(0); } else { return value; } @@ -152,35 +172,6 @@ public static PyStatResult fromDosFileAttributes(int mode, DosFileAttributes sta Py.newFloat(fromFileTime(stat.creationTime()))); } - // Override pyget, getslice to preserve backwards compatiblity that ints are returned for time elements - // if accessing by an index or slice - - private final static int ST_ATIME = 7; - private final static int ST_MTIME = 8; - private final static int ST_CTIME = 9; - - @Override - public PyObject pyget(int index) { - if (index == ST_ATIME || index == ST_MTIME || index == ST_CTIME) { - return super.pyget(index).__int__(); - } else { - return super.pyget(index); - } - } - - @Override - protected PyObject getslice(int start, int stop, int step) { - if (step > 0 && stop < start) { - stop = start; - } - int n = sliceLength(start, stop, step); - PyObject[] newArray = new PyObject[n]; - for (int i = start, j = 0; j < n; i += step, j++) { - newArray[j] = pyget(i); - } - return new PyTuple(newArray, false); - } - @Override public synchronized PyObject __eq__(PyObject o) { return stat_result___eq__(o); @@ -232,7 +223,11 @@ final PyObject stat_result___reduce__() { @Override public PyTuple __getnewargs__() { - return new PyTuple(new PyList(getArray())); + PyList lst = new PyList(getArray()); + lst.pyset(7, st_atime); + lst.pyset(8, st_mtime); + lst.pyset(9, st_ctime); + return new PyTuple(lst); } @Override @@ -244,55 +239,16 @@ public PyString __repr__() { } - /* Traverseproc implementation */ + /* Traverseproc implementation + * Note that there are more fields to traverse. However traverse in PyTuple handles those. + * Here we only traverse values that are not exactly referenced in PyTuple entries. + */ @Override public int traverse(Visitproc visit, Object arg) { int retVal = super.traverse(visit, arg); if (retVal != 0) { return retVal; } - if (st_mode != null) { - retVal = visit.visit(st_mode, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_ino != null) { - retVal = visit.visit(st_ino, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_dev != null) { - retVal = visit.visit(st_dev, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_nlink != null) { - retVal = visit.visit(st_nlink, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_uid != null) { - retVal = visit.visit(st_uid, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_gid != null) { - retVal = visit.visit(st_gid, arg); - if (retVal != 0) { - return retVal; - } - } - if (st_size != null) { - retVal = visit.visit(st_size, arg); - if (retVal != 0) { - return retVal; - } - } if (st_atime != null) { retVal = visit.visit(st_atime, arg); if (retVal != 0) { @@ -310,8 +266,7 @@ public int traverse(Visitproc visit, Object arg) { @Override public boolean refersDirectlyTo(PyObject ob) { - return ob != null && (ob == st_mode || ob == st_ino || ob == st_dev || ob == st_nlink - || ob == st_uid || ob == st_gid || ob == st_size || ob == st_atime - || ob == st_mtime || ob == st_ctime || super.refersDirectlyTo(ob)); + return ob != null && (ob == st_atime || ob == st_mtime + || ob == st_ctime || super.refersDirectlyTo(ob)); } } diff --git a/src/org/python/modules/posix/PythonPOSIXHandler.java b/src/org/python/modules/posix/PythonPOSIXHandler.java index 9c70e1e68..4217c1dc1 100644 --- a/src/org/python/modules/posix/PythonPOSIXHandler.java +++ b/src/org/python/modules/posix/PythonPOSIXHandler.java @@ -4,12 +4,14 @@ import java.io.File; import java.io.InputStream; import java.io.PrintStream; +import java.util.logging.Level; import jnr.constants.platform.Errno; import jnr.posix.POSIXHandler; import org.python.core.imp; import org.python.core.Options; +import org.python.core.PrePy; import org.python.core.Py; import org.python.core.PyObject; @@ -19,14 +21,17 @@ */ public class PythonPOSIXHandler implements POSIXHandler { + @Override public void error(Errno error, String extraData) { throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } + @Override public void error(Errno error, String methodName, String extraData) { throw Py.OSError(error, Py.newStringOrUnicode(extraData)); } + @Override public void unimplementedError(String methodName) { if (methodName.startsWith("stat.")) { // Ignore unimplemented FileStat methods @@ -35,17 +40,22 @@ public void unimplementedError(String methodName) { throw Py.NotImplementedError(methodName); } + @Override public void warn(WARNING_ID id, String message, Object... data) { } + @Override public boolean isVerbose() { - return Options.verbose >= Py.DEBUG; + // Verbose if the general threshold for logging is FINE or lower. + return PrePy.getLoggingLevel().intValue() <= Level.FINE.intValue(); } + @Override public File getCurrentWorkingDirectory() { return new File(Py.getSystemState().getCurrentWorkingDir()); } + @Override public String[] getEnv() { PyObject items = imp.load("os").__getattr__("environ").invoke("items"); String[] env = new String[items.__len__()]; @@ -56,18 +66,22 @@ public String[] getEnv() { return env; } + @Override public InputStream getInputStream() { return System.in; } + @Override public PrintStream getOutputStream() { return System.out; } + @Override public int getPID() { return 0; } + @Override public PrintStream getErrorStream() { return System.err; } diff --git a/src/org/python/modules/random/PyRandomDerived.java b/src/org/python/modules/random/PyRandomDerived.java index 56da2c046..0edf50d8a 100644 --- a/src/org/python/modules/random/PyRandomDerived.java +++ b/src/org/python/modules/random/PyRandomDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/modules/sre/PatternObject.java b/src/org/python/modules/sre/PatternObject.java index bc7ace4f4..490fb8960 100644 --- a/src/org/python/modules/sre/PatternObject.java +++ b/src/org/python/modules/sre/PatternObject.java @@ -404,21 +404,19 @@ private static PyString extractPyString(ArgParser ap, int pos) { if (obj instanceof PyString) { // Easy case - return (PyString)obj; + return (PyString) obj; - } else if (obj instanceof BufferProtocol) { + } else { // Try to get a byte-oriented buffer - try (PyBuffer buf = ((BufferProtocol)obj).getBuffer(PyBUF.FULL_RO)){ - // ... and treat those bytes as a PyString + try (PyBuffer buf = ((BufferProtocol) obj).getBuffer(PyBUF.SIMPLE)) { + // ... and wrap those bytes as a PyString return new PyString(buf.toString()); + } catch (ClassCastException e) { + throw Py.TypeError("expected string or buffer, but got " + obj.getType()); } } - - // Neither of those things worked - throw Py.TypeError("expected string or buffer, but got " + obj.getType()); } - /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { diff --git a/src/org/python/modules/sre/SRE_STATE.java b/src/org/python/modules/sre/SRE_STATE.java index afb9dcf43..50c352dbd 100644 --- a/src/org/python/modules/sre/SRE_STATE.java +++ b/src/org/python/modules/sre/SRE_STATE.java @@ -25,16 +25,16 @@ import org.python.core.PyString; public class SRE_STATE { - + /* * Generated from Python-2.4.5 like 'python headerToJava.py < Modules/sre_constants.h' - * where headerToJava.py contains the following code + * where headerToJava.py contains the following code import sys for line in sys.stdin: if line.startswith('#define'): line = line.replace('#define', 'public static final int').strip() segs = line.split(' ') - print '%s = %s;' % (' '.join(segs[:-1]), segs[-1]) + print '%s = %s;' % (' '.join(segs[:-1]), segs[-1]) */ //BEGIN generated code public static final int SRE_MAGIC = 20031017; @@ -114,7 +114,7 @@ public class SRE_STATE { //From here we're including things from _sre.c in the order they're defined there public static final int USE_RECURSION_LIMIT = 5000; - + /* error codes */ public static final int SRE_ERROR_ILLEGAL = -1; public static final int SRE_ERROR_STATE = -2; @@ -194,7 +194,7 @@ final boolean SRE_UNI_IS_LINEBREAK(int ch) { return false; } } - + final boolean sre_category(int category, int ch) { switch (category) { @@ -230,9 +230,11 @@ final boolean sre_category(int category, int ch) { return !Character.isDigit(ch); case SRE_CATEGORY_UNI_SPACE: - return Character.isSpaceChar(ch) || Character.isWhitespace(ch) || ch == 0x0085; + return Character.isSpaceChar(ch) || Character.isWhitespace(ch) || + ch == 0x0085 || ch == 0x180e; case SRE_CATEGORY_UNI_NOT_SPACE: - return !(Character.isSpaceChar(ch) || Character.isWhitespace(ch) || ch == 0x0085); + return !(Character.isSpaceChar(ch) || Character.isWhitespace(ch) || + ch == 0x0085 || ch == 0x180e); case SRE_CATEGORY_UNI_WORD: return Character.isLetterOrDigit(ch) || ch == '_'; @@ -293,7 +295,7 @@ private int mark_save(int lo, int hi) { // XXX => data_stack_grow in 2.4 } private void mark_restore(int lo, int hi, int mark_stack_base) { - + if (hi <= lo) return; @@ -305,7 +307,7 @@ private void mark_restore(int lo, int hi, int mark_stack_base) { System.arraycopy(mark_stack, this.mark_stack_base, mark, lo, size); } - + final boolean SRE_AT(int ptr, int at) { /* check if pointer is at given position. */ @@ -376,7 +378,7 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { case SRE_OP_FAILURE: // TRACE(setidx, ch, "CHARSET FAILURE"); return !ok; - + case SRE_OP_LITERAL: // TRACE(setidx, ch, "CHARSET LITERAL " + set[setidx]); /* */ @@ -384,7 +386,7 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { return ok; setidx++; break; - + case SRE_OP_CATEGORY: /* */ // TRACE(setidx, ch, "CHARSET CHARSET " + set[setidx]); @@ -400,13 +402,13 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { // (set[setidx + (ch >> 4)] & (1 << (ch & 15))) != 0) // return ok; // setidx += 16; - + /* (32 bits per code word) */ if (ch < 256 && (set[setidx + (ch >> 5)] & (1 << (ch & 31))) != 0) return ok; setidx += 8; break; - + case SRE_OP_RANGE: /* */ // TRACE(setidx, ch, "CHARSET RANGE " + set[setidx] + " " + set[setidx+1]); @@ -419,11 +421,11 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { // TRACE(setidx, ch, "CHARSET NEGATE"); ok = !ok; break; - + case SRE_OP_BIGCHARSET: /* <256 blockindices> */ // TRACE(setidx, ch, "CHARSET BIGCHARSET "); - + // count = *(set++); // if (!(ch & ~65535)) // block = ((unsigned char*)set)[ch >> 8]; @@ -434,7 +436,7 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { // (set[block*8 + ((ch & 255)>>5)] & (1 << (ch & 31)))) // return ok; // set += count*8; - + int count = set[setidx++]; int block; if (ch < 65536) @@ -444,7 +446,7 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { setidx += 64; if (block >= 0 && (set[setidx + block*8 + ((ch & 255)>>5)] & (1 << (ch & 31))) != 0) return ok; - setidx += count * 8; + setidx += count * 8; break; default: @@ -455,7 +457,7 @@ final boolean SRE_CHARSET(int[] set, int setidx, int ch) { } } } - + private int SRE_COUNT(int[] pattern, int pidx, int maxcount, int level) { int chr; int ptr = this.ptr; @@ -474,7 +476,7 @@ private int SRE_COUNT(int[] pattern, int pidx, int maxcount, int level) { while (ptr < end && SRE_CHARSET(pattern, pidx + 2, str[ptr])) ptr++; break; - + case SRE_OP_ANY: /* repeated dot wildcard. */ // TRACE(pidx, ptr, "COUNT ANY"); @@ -600,7 +602,7 @@ final int SRE_MATCH(int[] pattern, int pidx, int level) { pidx++; ptr++; break; - + case SRE_OP_SUCCESS: /* end of pattern */ // TRACE(pidx, ptr, "SUCCESS"); @@ -758,7 +760,7 @@ final int SRE_MATCH(int[] pattern, int pidx, int level) { } lastmark = this.lastmark; lastindex = this.lastindex; - + if (pattern[pidx + pattern[pidx]] == SRE_OP_LITERAL) { /* tail starts with a literal. skip positions where the rest of the pattern cannot possibly match */ @@ -796,7 +798,7 @@ final int SRE_MATCH(int[] pattern, int pidx, int level) { } } return 0; - + case SRE_OP_MIN_REPEAT_ONE: /* match repeated sequence (minimizing regexp) */ @@ -962,7 +964,7 @@ by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ this.ptr = ptr; return 0; } - + lastmark = this.lastmark; lastindex = this.lastindex; @@ -989,7 +991,7 @@ by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ this.ptr = ptr; return 0; - + case SRE_OP_GROUPREF: /* match backreference */ i = pattern[pidx]; @@ -1023,7 +1025,7 @@ by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ } pidx++; break; - + case SRE_OP_GROUPREF_EXISTS: i = pattern[pidx]; // TRACE(pidx, ptr, "GROUPREF_EXISTS " + i); @@ -1035,7 +1037,7 @@ by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ } pidx += 2; break; - + case SRE_OP_ASSERT: /* assert subpattern */ /* args: */ @@ -1064,7 +1066,7 @@ by the UNTIL operator (MAX_UNTIL, MIN_UNTIL) */ } pidx += pattern[pidx]; break; - + case SRE_OP_FAILURE: /* immediate failure */ // TRACE(pidx, ptr, "FAILURE"); @@ -1087,7 +1089,7 @@ private void LASTMARK_RESTORE(int lastmark, int lastindex) { this.lastindex = lastindex; } } - + int SRE_SEARCH(int[] pattern, int pidx) { int ptr = this.start; int end = this.end; @@ -1328,7 +1330,7 @@ public static int getlower(int ch, int flags) { } // XXX - this is not UTF-16 compliant; also depends on whether from PyString or PyUnicode - + String getslice(int index, String string, boolean empty) { int i, j; diff --git a/src/org/python/modules/struct.java b/src/org/python/modules/struct.java index b34f4815e..9e2b5556f 100644 --- a/src/org/python/modules/struct.java +++ b/src/org/python/modules/struct.java @@ -1,14 +1,15 @@ -/* - * Copyright 1999 Finn Bock. - * - * This program contains material copyrighted by: - * Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam, - * The Netherlands. - */ +// (c)2019 Jython Developers. Licensed to PSF under a Contributor Agreement. +// +// First Java version copyright 1999 Finn Bock also contains material Copyright 1991-1995 by +// Stichting Mathematisch Centrum, Amsterdam, The Netherlands. package org.python.modules; +import org.python.core.ClassDictInit; import org.python.core.Py; +import org.python.core.Py2kBuffer; +import org.python.core.PyArray; +import org.python.core.PyByteArray; import org.python.core.PyException; import org.python.core.PyFloat; import org.python.core.PyList; @@ -19,9 +20,9 @@ import org.python.core.PyTuple; import java.math.BigInteger; -import org.python.core.ClassDictInit; -import org.python.core.PyArray; + +//@formatter:off /** * This module performs conversions between Python values and C * structs represented as Python strings. It uses format strings @@ -30,89 +31,81 @@ * *

    * The module defines the following exception and functions: - * - *

    - *

    error + *
    + *
    error
    *
    * Exception raised on various occasions; argument is a string * describing what is wrong. - *
    - * - *

    - *

    pack (fmt, v1, v2, ...) + * + *
    pack (fmt, v1, v2, ...)
    *
    * Return a string containing the values * v1, v2, ... packed according to the given * format. The arguments must match the values required by the format * exactly. - *
    - * - *

    - *

    unpack> (fmt, string) + * + *
    unpack (fmt, string)
    *
    * Unpack the string (presumably packed by pack(fmt, * ...)) according to the given format. The result is a * tuple even if it contains exactly one item. The string must contain * exactly the amount of data required by the format (i.e. * len(string) must equal calcsize(fmt)). - *
    - * - *

    - *

    calcsize (fmt) + * + *
    calcsize (fmt)
    *
    * Return the size of the struct (and hence of the string) * corresponding to the given format. *
    * - *

    * Format characters have the following meaning; the conversion between * C and Python values should be obvious given their types: - * - *

    - *

    Effect of padding on {@link #start} or {@link #lenWhole}
    alignmeaningresult.length()
    <{@code <}left-aligned+0+0+n
    >{@code >}right-aligned+n+0+n
    ^{@code ^}centred+(n/2)+0+n
    ={@code =}pad after sign+0+n
    + + *
    + * * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * *
    Format characters
    FormatC TypePython
    x
    {@code x}pad byteno value
    c
    {@code c}charstring of length 1
    b
    {@code b}signed charinteger
    B
    {@code B}unsigned charinteger
    h
    {@code h}shortinteger
    H
    {@code H}unsigned shortinteger
    i
    {@code i}intinteger
    I
    {@code I}unsigned intinteger
    size
    {@code size}longinteger
    L
    {@code L}unsigned longinteger
    f
    {@code f}floatfloat
    d
    {@code d}doublefloat
    s
    {@code s}char[]string
    p
    {@code p}char[]string
    @@ -160,24 +153,24 @@ * according to the following table: * *

    - * - * + *
    + * * * * - * + * * * - * + * * * - * + * * * - * + * * * - * + * * * * @@ -221,19 +214,16 @@ * *

    * Examples (all using native byte order, size and alignment, on a - * big-endian machine): - * - *

    - *

    - * >>> from struct import *
    - * >>> pack('hhl', 1, 2, 3)
    + * big-endian machine): 
    {@literal
    + * >>> from struct import *
    + * >>> pack('hhl', 1, 2, 3)
      * '\000\001\000\002\000\000\000\003'
    - * >>> unpack('hhl', '\000\001\000\002\000\000\000\003')
    + * >>> unpack('hhl', '\000\001\000\002\000\000\000\003')
      * (1, 2, 3)
    - * >>> calcsize('hhl')
    + * >>> calcsize('hhl')
      * 8
    - * >>>
    - * 
    + * >>> + * } * *

    * Hint: to align the end of a structure to the alignment requirement of @@ -253,14 +243,13 @@ * @author Finn Bock, bckfnn@pipmail.dknet.dk * @version struct.java,v 1.6 1999/04/17 12:04:34 fb Exp */ +//@formatter:on public class struct implements ClassDictInit { - /** - * Exception raised on various occasions; argument is a - * string describing what is wrong. - */ + /** Exception raised on various occasions; argument is a string describing what is wrong. */ public static final PyObject error = Py.makeClass("error", Py.Exception, exceptionNamespace()); + //@formatter:off public static String __doc__ = "Functions to convert between Python values and C structs.\n" + "Python strings are used to hold the data representing the C\n" + @@ -285,9 +274,10 @@ public class struct implements ClassDictInit { "Whitespace between formats is ignored.\n" + "\n" + "The variable struct.error is an exception raised on errors."; - + //@formatter:on static class FormatDef { + char name; int size; int alignment; @@ -299,28 +289,30 @@ FormatDef init(char name, int size, int alignment) { return this; } - void pack(ByteStream buf, PyObject value) {} + void pack(ByteStream buf, PyObject value) {} Object unpack(ByteStream buf) { return null; } int doPack(ByteStream buf, int count, int pos, PyObject[] args) { - if (pos + count > args.length) + if (pos + count > args.length) { throw StructError("insufficient arguments to pack"); + } int cnt = count; - while (count-- > 0) + while (count-- > 0) { pack(buf, args[pos++]); + } return cnt; } void doUnpack(ByteStream buf, int count, PyList list) { - while (count-- > 0) + while (count-- > 0) { list.append(Py.java2py(unpack(buf))); + } } - int get_int(PyObject value) { try { return value.asInt(); @@ -330,42 +322,43 @@ int get_int(PyObject value) { } long get_long(PyObject value) { - if (value instanceof PyLong){ + if (value instanceof PyLong) { Object v = value.__tojava__(Long.TYPE); if (v == Py.NoConversion) { throw StructError("long int too long to convert"); } return ((Long) v).longValue(); - } else + } else { return get_int(value); + } } BigInteger get_ulong(PyObject value) { - if (value instanceof PyLong){ - BigInteger v = (BigInteger)value.__tojava__(BigInteger.class); - if (v.compareTo(PyLong.MAX_ULONG) > 0){ + if (value instanceof PyLong) { + BigInteger v = (BigInteger) value.__tojava__(BigInteger.class); + if (v.compareTo(PyLong.MAX_ULONG) > 0) { throw StructError("unsigned long int too long to convert"); } return v; - } else + } else { return BigInteger.valueOf(get_int(value)); + } } double get_float(PyObject value) { return value.asDouble(); } - void BEwriteInt(ByteStream buf, int v) { buf.writeByte((v >>> 24) & 0xFF); buf.writeByte((v >>> 16) & 0xFF); - buf.writeByte((v >>> 8) & 0xFF); - buf.writeByte((v >>> 0) & 0xFF); + buf.writeByte((v >>> 8) & 0xFF); + buf.writeByte((v >>> 0) & 0xFF); } void LEwriteInt(ByteStream buf, int v) { - buf.writeByte((v >>> 0) & 0xFF); - buf.writeByte((v >>> 8) & 0xFF); + buf.writeByte((v >>> 0) & 0xFF); + buf.writeByte((v >>> 8) & 0xFF); buf.writeByte((v >>> 16) & 0xFF); buf.writeByte((v >>> 24) & 0xFF); } @@ -387,8 +380,8 @@ int LEreadInt(ByteStream buf) { } } - static class ByteStream { + char[] data; int len; int pos; @@ -402,15 +395,16 @@ static class ByteStream { ByteStream(String s) { this(s, 0); } - + ByteStream(String s, int offset) { int size = s.length() - offset; data = new char[size]; s.getChars(offset, s.length(), data, 0); len = size; pos = 0; - -// System.out.println("s.length()=" + s.length() + ",offset=" + offset + ",size=" + size + ",data=" + Arrays.toString(data)); + +// System.out.println("s.length()=" + s.length() + ",offset=" + offset + ",size=" + size + ",data=" +// + Arrays.toString(data)); } int readByte() { @@ -422,14 +416,12 @@ void read(char[] buf, int pos, int len) { this.pos += len; } - String readString(int l) { char[] data = new char[l]; read(data, 0, l); return new String(data); } - private void ensureCapacity(int l) { if (pos + l >= data.length) { char[] b = new char[(pos + l) * 2]; @@ -438,13 +430,11 @@ private void ensureCapacity(int l) { } } - void writeByte(int b) { ensureCapacity(1); - data[pos++] = (char)(b & 0xFF); + data[pos++] = (char) (b & 0xFF); } - void write(char[] buf, int pos, int len) { ensureCapacity(len); System.arraycopy(buf, pos, data, this.pos, len); @@ -457,7 +447,6 @@ void writeString(String s, int pos, int len) { write(data, 0, len); } - int skip(int l) { pos += l; return pos; @@ -467,317 +456,370 @@ int size() { return pos; } + @Override public String toString() { return new String(data, 0, pos); } } - static class PadFormatDef extends FormatDef { + + @Override int doPack(ByteStream buf, int count, int pos, PyObject[] args) { - while (count-- > 0) + while (count-- > 0) { buf.writeByte(0); + } return 0; } + @Override void doUnpack(ByteStream buf, int count, PyList list) { - while (count-- > 0) + while (count-- > 0) { buf.readByte(); + } } } - static class StringFormatDef extends FormatDef { + + @Override int doPack(ByteStream buf, int count, int pos, PyObject[] args) { PyObject value = args[pos]; - if (!(value instanceof PyString)) + if (!(value instanceof PyString)) { throw StructError("argument for 's' must be a string"); + } String s = value.toString(); int len = s.length(); buf.writeString(s, 0, Math.min(count, len)); if (len < count) { count -= len; - for (int i = 0; i < count; i++) + for (int i = 0; i < count; i++) { buf.writeByte(0); + } } return 1; } + @Override void doUnpack(ByteStream buf, int count, PyList list) { list.append(Py.newString(buf.readString(count))); } } - static class PascalStringFormatDef extends StringFormatDef { + + @Override int doPack(ByteStream buf, int count, int pos, PyObject[] args) { PyObject value = args[pos]; - if (!(value instanceof PyString)) + if (!(value instanceof PyString)) { throw StructError("argument for 'p' must be a string"); + } - buf.writeByte(Math.min(0xFF, Math.min(value.toString().length(), count-1))); - return super.doPack(buf, count-1, pos, args); + buf.writeByte(Math.min(0xFF, Math.min(value.toString().length(), count - 1))); + return super.doPack(buf, count - 1, pos, args); } + @Override void doUnpack(ByteStream buf, int count, PyList list) { int n = buf.readByte(); - if (n >= count) - n = count-1; + if (n >= count) { + n = count - 1; + } super.doUnpack(buf, n, list); - buf.skip(Math.max(count-n-1, 0)); + buf.skip(Math.max(count - n - 1, 0)); } } - static class CharFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - if (!(value instanceof PyString) || value.__len__() != 1) + if (!(value instanceof PyString) || value.__len__() != 1) { throw StructError("char format require string of length 1"); + } buf.writeByte(value.toString().charAt(0)); } + @Override Object unpack(ByteStream buf) { - return Py.newString((char)buf.readByte()); + return Py.newString((char) buf.readByte()); } } - static class ByteFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { buf.writeByte(get_int(value)); } + @Override Object unpack(ByteStream buf) { int b = buf.readByte(); - if (b > Byte.MAX_VALUE) + if (b > Byte.MAX_VALUE) { b -= 0x100; + } return Py.newInteger(b); } } static class UnsignedByteFormatDef extends ByteFormatDef { + + @Override Object unpack(ByteStream buf) { return Py.newInteger(buf.readByte()); } } - + static class PointerFormatDef extends FormatDef { + FormatDef init(char name) { String dataModel = System.getProperty("sun.arch.data.model"); - if (dataModel == null) + if (dataModel == null) { throw Py.NotImplementedError("Can't determine if JVM is 32- or 64-bit"); + } int length = dataModel.equals("64") ? 8 : 4; super.init(name, length, length); return this; } - + + @Override void pack(ByteStream buf, PyObject value) { throw Py.NotImplementedError("Pointer packing/unpacking not implemented in Jython"); } + @Override Object unpack(ByteStream buf) { throw Py.NotImplementedError("Pointer packing/unpacking not implemented in Jython"); } } - + static class LEShortFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { int v = get_int(value); buf.writeByte(v & 0xFF); buf.writeByte((v >> 8) & 0xFF); } + @Override Object unpack(ByteStream buf) { - int v = buf.readByte() | - (buf.readByte() << 8); - if (v > Short.MAX_VALUE) - v -= 0x10000 ; + int v = buf.readByte() | (buf.readByte() << 8); + if (v > Short.MAX_VALUE) { + v -= 0x10000; + } return Py.newInteger(v); } } static class LEUnsignedShortFormatDef extends LEShortFormatDef { + + @Override Object unpack(ByteStream buf) { - int v = buf.readByte() | - (buf.readByte() << 8); + int v = buf.readByte() | (buf.readByte() << 8); return Py.newInteger(v); } } - static class BEShortFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { int v = get_int(value); buf.writeByte((v >> 8) & 0xFF); buf.writeByte(v & 0xFF); } + @Override Object unpack(ByteStream buf) { - int v = (buf.readByte() << 8) | - buf.readByte(); - if (v > Short.MAX_VALUE) + int v = (buf.readByte() << 8) | buf.readByte(); + if (v > Short.MAX_VALUE) { v -= 0x10000; + } return Py.newInteger(v); } } - static class BEUnsignedShortFormatDef extends BEShortFormatDef { + + @Override Object unpack(ByteStream buf) { - int v = (buf.readByte() << 8) | - buf.readByte(); + int v = (buf.readByte() << 8) | buf.readByte(); return Py.newInteger(v); } } - static class LEIntFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { LEwriteInt(buf, get_int(value)); } + @Override Object unpack(ByteStream buf) { int v = LEreadInt(buf); return Py.newInteger(v); } } - static class LEUnsignedIntFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - LEwriteInt(buf, (int)(get_long(value) & 0xFFFFFFFF)); + LEwriteInt(buf, (int) (get_long(value) & 0xFFFFFFFF)); } + @Override Object unpack(ByteStream buf) { long v = LEreadInt(buf); - if (v < 0) + if (v < 0) { v += 0x100000000L; + } return new PyLong(v); } } - static class BEIntFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { BEwriteInt(buf, get_int(value)); } + @Override Object unpack(ByteStream buf) { return Py.newInteger(BEreadInt(buf)); } } - static class BEUnsignedIntFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - BEwriteInt(buf, (int)(get_long(value) & 0xFFFFFFFF)); + BEwriteInt(buf, (int) (get_long(value) & 0xFFFFFFFF)); } + + @Override Object unpack(ByteStream buf) { long v = BEreadInt(buf); - if (v < 0) + if (v < 0) { v += 0x100000000L; + } return new PyLong(v); } } static class LEUnsignedLongFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { BigInteger bi = get_ulong(value); if (bi.compareTo(BigInteger.valueOf(0)) < 0) { throw StructError("can't convert negative long to unsigned"); } long lvalue = bi.longValue(); // underflow is OK -- the bits are correct - int high = (int) ( (lvalue & 0xFFFFFFFF00000000L)>>32 ); - int low = (int) ( lvalue & 0x00000000FFFFFFFFL ); - LEwriteInt( buf, low ); - LEwriteInt( buf, high ); + int high = (int) ((lvalue & 0xFFFFFFFF00000000L) >> 32); + int low = (int) (lvalue & 0x00000000FFFFFFFFL); + LEwriteInt(buf, low); + LEwriteInt(buf, high); } + @Override Object unpack(ByteStream buf) { - long low = ( LEreadInt( buf ) & 0X00000000FFFFFFFFL ); - long high = ( LEreadInt( buf ) & 0X00000000FFFFFFFFL ); - java.math.BigInteger result=java.math.BigInteger.valueOf(high); - result=result.multiply(java.math.BigInteger.valueOf(0x100000000L)); - result=result.add(java.math.BigInteger.valueOf(low)); + long low = (LEreadInt(buf) & 0X00000000FFFFFFFFL); + long high = (LEreadInt(buf) & 0X00000000FFFFFFFFL); + java.math.BigInteger result = java.math.BigInteger.valueOf(high); + result = result.multiply(java.math.BigInteger.valueOf(0x100000000L)); + result = result.add(java.math.BigInteger.valueOf(low)); return new PyLong(result); } } - static class BEUnsignedLongFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { BigInteger bi = get_ulong(value); if (bi.compareTo(BigInteger.valueOf(0)) < 0) { throw StructError("can't convert negative long to unsigned"); } long lvalue = bi.longValue(); // underflow is OK -- the bits are correct - int high = (int) ( (lvalue & 0xFFFFFFFF00000000L)>>32 ); - int low = (int) ( lvalue & 0x00000000FFFFFFFFL ); - BEwriteInt( buf, high ); - BEwriteInt( buf, low ); + int high = (int) ((lvalue & 0xFFFFFFFF00000000L) >> 32); + int low = (int) (lvalue & 0x00000000FFFFFFFFL); + BEwriteInt(buf, high); + BEwriteInt(buf, low); } + @Override Object unpack(ByteStream buf) { - long high = ( BEreadInt( buf ) & 0X00000000FFFFFFFFL ); - long low = ( BEreadInt( buf ) & 0X00000000FFFFFFFFL ); - java.math.BigInteger result=java.math.BigInteger.valueOf(high); - result=result.multiply(java.math.BigInteger.valueOf(0x100000000L)); - result=result.add(java.math.BigInteger.valueOf(low)); + long high = (BEreadInt(buf) & 0X00000000FFFFFFFFL); + long low = (BEreadInt(buf) & 0X00000000FFFFFFFFL); + java.math.BigInteger result = java.math.BigInteger.valueOf(high); + result = result.multiply(java.math.BigInteger.valueOf(0x100000000L)); + result = result.add(java.math.BigInteger.valueOf(low)); return new PyLong(result); } } - static class LELongFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - long lvalue = get_long( value ); - int high = (int) ( (lvalue & 0xFFFFFFFF00000000L)>>32 ); - int low = (int) ( lvalue & 0x00000000FFFFFFFFL ); - LEwriteInt( buf, low ); - LEwriteInt( buf, high ); + long lvalue = get_long(value); + int high = (int) ((lvalue & 0xFFFFFFFF00000000L) >> 32); + int low = (int) (lvalue & 0x00000000FFFFFFFFL); + LEwriteInt(buf, low); + LEwriteInt(buf, high); } + @Override Object unpack(ByteStream buf) { long low = LEreadInt(buf) & 0x00000000FFFFFFFFL; - long high = ((long)(LEreadInt(buf))<<32) & 0xFFFFFFFF00000000L; - long result=(high|low); + long high = ((long) (LEreadInt(buf)) << 32) & 0xFFFFFFFF00000000L; + long result = (high | low); return new PyLong(result); } } - static class BELongFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - long lvalue = get_long( value ); - int high = (int) ( (lvalue & 0xFFFFFFFF00000000L)>>32 ); - int low = (int) ( lvalue & 0x00000000FFFFFFFFL ); - BEwriteInt( buf, high ); - BEwriteInt( buf, low ); + long lvalue = get_long(value); + int high = (int) ((lvalue & 0xFFFFFFFF00000000L) >> 32); + int low = (int) (lvalue & 0x00000000FFFFFFFFL); + BEwriteInt(buf, high); + BEwriteInt(buf, low); } + @Override Object unpack(ByteStream buf) { - long high = ((long)(BEreadInt(buf))<<32) & 0xFFFFFFFF00000000L; + long high = ((long) (BEreadInt(buf)) << 32) & 0xFFFFFFFF00000000L; long low = BEreadInt(buf) & 0x00000000FFFFFFFFL; - long result=(high|low); + long result = (high | low); return new PyLong(result); } } - static class LEFloatFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - int bits = Float.floatToIntBits((float)get_float(value)); + int bits = Float.floatToIntBits((float) get_float(value)); LEwriteInt(buf, bits); } + @Override Object unpack(ByteStream buf) { int bits = LEreadInt(buf); float v = Float.intBitsToFloat(bits); - if (PyFloat.float_format == PyFloat.Format.UNKNOWN && ( - Float.isInfinite(v) || Float.isNaN(v))) { + if (PyFloat.float_format == PyFloat.Format.UNKNOWN + && (Float.isInfinite(v) || Float.isNaN(v))) { throw Py.ValueError("can't unpack IEEE 754 special value on non-IEEE platform"); } return Py.newFloat(v); @@ -785,36 +827,40 @@ Object unpack(ByteStream buf) { } static class LEDoubleFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { long bits = Double.doubleToLongBits(get_float(value)); - LEwriteInt(buf, (int)(bits & 0xFFFFFFFF)); - LEwriteInt(buf, (int)(bits >>> 32)); + LEwriteInt(buf, (int) (bits & 0xFFFFFFFF)); + LEwriteInt(buf, (int) (bits >>> 32)); } + @Override Object unpack(ByteStream buf) { - long bits = (LEreadInt(buf) & 0xFFFFFFFFL) + - (((long)LEreadInt(buf)) << 32); + long bits = (LEreadInt(buf) & 0xFFFFFFFFL) + (((long) LEreadInt(buf)) << 32); double v = Double.longBitsToDouble(bits); - if (PyFloat.double_format == PyFloat.Format.UNKNOWN && - (Double.isInfinite(v) || Double.isNaN(v))) { + if (PyFloat.double_format == PyFloat.Format.UNKNOWN + && (Double.isInfinite(v) || Double.isNaN(v))) { throw Py.ValueError("can't unpack IEEE 754 special value on non-IEEE platform"); } return Py.newFloat(v); } } - static class BEFloatFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { - int bits = Float.floatToIntBits((float)get_float(value)); + int bits = Float.floatToIntBits((float) get_float(value)); BEwriteInt(buf, bits); } + @Override Object unpack(ByteStream buf) { int bits = BEreadInt(buf); float v = Float.intBitsToFloat(bits); - if (PyFloat.float_format == PyFloat.Format.UNKNOWN && ( - Float.isInfinite(v) || Float.isNaN(v))) { + if (PyFloat.float_format == PyFloat.Format.UNKNOWN + && (Float.isInfinite(v) || Float.isNaN(v))) { throw Py.ValueError("can't unpack IEEE 754 special value on non-IEEE platform"); } return Py.newFloat(v); @@ -822,25 +868,27 @@ Object unpack(ByteStream buf) { } static class BEDoubleFormatDef extends FormatDef { + + @Override void pack(ByteStream buf, PyObject value) { long bits = Double.doubleToLongBits(get_float(value)); - BEwriteInt(buf, (int)(bits >>> 32)); - BEwriteInt(buf, (int)(bits & 0xFFFFFFFF)); + BEwriteInt(buf, (int) (bits >>> 32)); + BEwriteInt(buf, (int) (bits & 0xFFFFFFFF)); } + @Override Object unpack(ByteStream buf) { - long bits = (((long) BEreadInt(buf)) << 32) + - (BEreadInt(buf) & 0xFFFFFFFFL); + long bits = (((long) BEreadInt(buf)) << 32) + (BEreadInt(buf) & 0xFFFFFFFFL); double v = Double.longBitsToDouble(bits); - if (PyFloat.double_format == PyFloat.Format.UNKNOWN && - (Double.isInfinite(v) || Double.isNaN(v))) { + if (PyFloat.double_format == PyFloat.Format.UNKNOWN + && (Double.isInfinite(v) || Double.isNaN(v))) { throw Py.ValueError("can't unpack IEEE 754 special value on non-IEEE platform"); } return Py.newFloat(v); } } - + //@formatter:off private static FormatDef[] lilendian_table = { new PadFormatDef() .init('x', 1, 0), new ByteFormatDef() .init('b', 1, 0), @@ -898,70 +946,66 @@ Object unpack(ByteStream buf) { new BEDoubleFormatDef() .init('d', 8, 8), new PointerFormatDef() .init('P') }; - - + //@formatter:on static FormatDef[] whichtable(String pfmt) { char c = pfmt.charAt(0); switch (c) { - case '<' : - return lilendian_table; - case '>': - case '!': - // Network byte order is big-endian - return bigendian_table; - case '=': - return bigendian_table; - case '@': - default: - return native_table; + case '<': + return lilendian_table; + case '>': + case '!': + // Network byte order is big-endian + return bigendian_table; + case '=': + return bigendian_table; + case '@': + default: + return native_table; } } - private static FormatDef getentry(char c, FormatDef[] f) { for (int i = 0; i < f.length; i++) { - if (f[i].name == c) + if (f[i].name == c) { return f[i]; + } } throw StructError("bad char in struct format"); } - - private static int align(int size, FormatDef e) { if (e.alignment != 0) { - size = ((size + e.alignment - 1) - / e.alignment) - * e.alignment; + size = ((size + e.alignment - 1) / e.alignment) * e.alignment; } return size; } - - static int calcsize(String format, FormatDef[] f) { int size = 0; int len = format.length(); for (int j = 0; j < len; j++) { char c = format.charAt(j); - if (j == 0 && (c=='@' || c=='<' || c=='>' || c=='=' || c=='!')) + if (j == 0 && (c == '@' || c == '<' || c == '>' || c == '=' || c == '!')) { continue; - if (Character.isWhitespace(c)) + } + if (Character.isWhitespace(c)) { continue; + } int num = 1; if (Character.isDigit(c)) { num = Character.digit(c, 10); - while (++j < len && - Character.isDigit((c = format.charAt(j)))) { - int x = num*10 + Character.digit(c, 10); - if (x/10 != num) + while (++j < len && Character.isDigit((c = format.charAt(j)))) { + int x = num * 10 + Character.digit(c, 10); + if (x / 10 != num) { throw StructError("overflow in item count"); + } num = x; } - if (j >= len) + if (j >= len) { break; + } } FormatDef e = getentry(c, f); @@ -970,69 +1014,70 @@ static int calcsize(String format, FormatDef[] f) { size = align(size, e); int x = num * itemsize; size += x; - if (x/itemsize != num || size < 0) + if (x / itemsize != num || size < 0) { throw StructError("total struct size too long"); + } } return size; } - /** - * Return the size of the struct (and hence of the string) - * corresponding to the given format. + * Return the size of the struct (and hence of the string) corresponding to the given format. */ static public int calcsize(String format) { FormatDef[] f = whichtable(format); return calcsize(format, f); } - /** - * Return a string containing the values v1, v2, ... packed according - * to the given format. The arguments must match the - * values required by the format exactly. + * Return a string containing the values v1, v2, ... packed according to the given format. The + * arguments must match the values required by the format exactly. */ static public PyString pack(PyObject[] args) { - if (args.length < 1) + if (args.length < 1) { Py.TypeError("illegal argument type for built-in operation"); + } String format = args[0].toString(); FormatDef[] f = whichtable(format); int size = calcsize(format, f); - + return new PyString(pack(format, f, size, 1, args).toString()); } - + // xxx - may need to consider doing a generic arg parser here static public void pack_into(PyObject[] args) { - if (args.length < 3) + if (args.length < 3) { Py.TypeError("illegal argument type for built-in operation"); + } String format = args[0].toString(); FormatDef[] f = whichtable(format); int size = calcsize(format, f); pack_into(format, f, size, 1, args); } - + static void pack_into(String format, FormatDef[] f, int size, int argstart, PyObject[] args) { - if (args.length - argstart < 2) + if (args.length - argstart < 2) { Py.TypeError("illegal argument type for built-in operation"); + } if (!(args[argstart] instanceof PyArray)) { throw Py.TypeError("pack_into takes an array arg"); // as well as a buffer, what else? } - PyArray buffer = (PyArray)args[argstart]; + PyArray buffer = (PyArray) args[argstart]; int offset = args[argstart + 1].asInt(); ByteStream res = pack(format, f, size, argstart + 2, args); if (res.pos > buffer.__len__()) { - throw StructError("pack_into requires a buffer of at least " + res.pos + " bytes, got " + buffer.__len__()); + throw StructError("pack_into requires a buffer of at least " + res.pos + " bytes, got " + + buffer.__len__()); } for (int i = 0; i < res.pos; i++, offset++) { char val = res.data[i]; buffer.set(offset, val); } } - + static ByteStream pack(String format, FormatDef[] f, int size, int start, PyObject[] args) { ByteStream res = new ByteStream(); @@ -1040,105 +1085,135 @@ static ByteStream pack(String format, FormatDef[] f, int size, int start, PyObje int len = format.length(); for (int j = 0; j < len; j++) { char c = format.charAt(j); - if (j == 0 && (c=='@' || c=='<' || c=='>' || c=='=' || c=='!')) + if (j == 0 && (c == '@' || c == '<' || c == '>' || c == '=' || c == '!')) { continue; - if (Character.isWhitespace(c)) + } + if (Character.isWhitespace(c)) { continue; + } int num = 1; if (Character.isDigit(c)) { num = Character.digit(c, 10); - while (++j < len && Character.isDigit((c = format.charAt(j)))) - num = num*10 + Character.digit(c, 10); - if (j >= len) + while (++j < len && Character.isDigit((c = format.charAt(j)))) { + num = num * 10 + Character.digit(c, 10); + } + if (j >= len) { break; + } } FormatDef e = getentry(c, f); // Fill pad bytes with zeros int nres = align(res.size(), e) - res.size(); - while (nres-- > 0) + while (nres-- > 0) { res.writeByte(0); + } i += e.doPack(res, num, i, args); } - if (i < args.length) + if (i < args.length) { throw StructError("too many arguments for pack format"); + } return res; } - - /** - * Unpack the string (presumably packed by pack(fmt, ...)) according - * to the given format. The result is a tuple even if it contains - * exactly one item. - * The string must contain exactly the amount of data required by - * the format (i.e. len(string) must equal calcsize(fmt)). + * Unpack the string (presumably packed by pack(fmt, ...)) according to the given format. The + * result is a tuple even if it contains exactly one item. The string must contain exactly the + * amount of data required by the format (i.e. len(string) must equal calcsize(fmt)). */ - + public static PyTuple unpack(String format, String string) { FormatDef[] f = whichtable(format); int size = calcsize(format, f); int len = string.length(); - if (size != len) + if (size != len) { throw StructError("unpack str size does not match format"); - return unpack(f, size, format, new ByteStream(string)); + } + return unpack(f, size, format, new ByteStream(string)); } - + public static PyTuple unpack(String format, PyArray buffer) { String string = buffer.tostring(); FormatDef[] f = whichtable(format); int size = calcsize(format, f); int len = string.length(); - if (size != len) + if (size != len) { throw StructError("unpack str size does not match format"); - return unpack(f, size, format, new ByteStream(string)); + } + return unpack(f, size, format, new ByteStream(string)); + } + + public static PyTuple unpack(String format, Py2kBuffer buffer) { + return unpack(format, buffer.toString()); + } + + public static PyTuple unpack(String format, PyByteArray bytearray) { + /* bytearray is added in 2.7.7 */ + return unpack(format, bytearray.toString()); + } + + public static PyTuple unpack_from(String format, Py2kBuffer buffer) { + return unpack_from(format, buffer.toString(), 0); + } + + public static PyTuple unpack_from(String format, PyByteArray bytearray) { + return unpack_from(format, bytearray.toString(), 0); + } + + public static PyTuple unpack_from(String format, Py2kBuffer buffer, int offset) { + return unpack_from(format, buffer.toString(), offset); } - + + public static PyTuple unpack_from(String format, PyByteArray bytearray, int offset) { + return unpack_from(format, bytearray.toString(), offset); + } + public static PyTuple unpack_from(String format, String string) { - return unpack_from(format, string, 0); + return unpack_from(format, string, 0); } - + public static PyTuple unpack_from(String format, String string, int offset) { FormatDef[] f = whichtable(format); int size = calcsize(format, f); int len = string.length(); - if (size >= (len - offset + 1)) + if (size >= (len - offset + 1)) { throw StructError("unpack_from str size does not match format"); + } return unpack(f, size, format, new ByteStream(string, offset)); } - + static PyTuple unpack(FormatDef[] f, int size, String format, ByteStream str) { PyList res = new PyList(); int flen = format.length(); for (int j = 0; j < flen; j++) { char c = format.charAt(j); - if (j == 0 && (c=='@' || c=='<' || c=='>' || c=='=' || c=='!')) + if (j == 0 && (c == '@' || c == '<' || c == '>' || c == '=' || c == '!')) { continue; - if (Character.isWhitespace(c)) + } + if (Character.isWhitespace(c)) { continue; + } int num = 1; if (Character.isDigit(c)) { num = Character.digit(c, 10); - while (++j < flen && - Character.isDigit((c = format.charAt(j)))) - num = num*10 + Character.digit(c, 10); - if (j > flen) + while (++j < flen && Character.isDigit((c = format.charAt(j)))) { + num = num * 10 + Character.digit(c, 10); + } + if (j > flen) { break; + } } FormatDef e = getentry(c, f); - str.skip(align(str.size(), e) - str.size()); - e.doUnpack(str, num, res); } return PyTuple.fromIterable(res); } - static PyException StructError(String explanation) { return new PyException(error, explanation); } @@ -1148,10 +1223,9 @@ private static PyObject exceptionNamespace() { dict.__setitem__("__module__", new PyString("struct")); return dict; } - + public static void classDictInit(PyObject dict) { dict.__setitem__("Struct", PyStruct.TYPE); } } - diff --git a/src/org/python/modules/thread/thread.java b/src/org/python/modules/thread/thread.java index 97cbd62db..02d57df13 100644 --- a/src/org/python/modules/thread/thread.java +++ b/src/org/python/modules/thread/thread.java @@ -61,17 +61,9 @@ public static FunctionThread _newFunctionThread(PyObject func, PyTuple args) { } /** - * Interrupts all running threads spawned by the thread module. - * - * This works in conjunction with:

    • - * {@link org.python.core.PyTableCode#call}: checks for the interrupted - * status of the current thread and raise a SystemRestart exception if a - * interruption is detected.
    • - *
    • {@link FunctionThread#run()}: exits the current thread when a - * SystemRestart exception is not caught.
    • - * - * Thus, it is possible that this doesn't make all running threads to stop, - * if SystemRestart exception is caught. + * Interrupt all running threads spawned by the thread module. This works in conjunction with: + * {@link org.python.core.PyTableCode#call}, which checks for the interrupted status of the + * current thread, and {@link FunctionThread#run()}, which exits the current thread. */ public static void interruptAllThreads() { group.interrupt(); @@ -92,7 +84,7 @@ public static void exit_thread() { public static long get_ident() { return Thread.currentThread().getId(); } - + public static long stack_size(PyObject[] args) { switch (args.length) { case 0: diff --git a/src/org/python/modules/time/Time.java b/src/org/python/modules/time/Time.java index bb4163d55..ebd98717d 100644 --- a/src/org/python/modules/time/Time.java +++ b/src/org/python/modules/time/Time.java @@ -12,12 +12,10 @@ // see org/python/modules/time.java for previous history. package org.python.modules.time; -import java.text.DateFormatSymbols; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; -import java.util.Locale; import java.util.TimeZone; import org.python.core.ClassDictInit; @@ -28,8 +26,11 @@ import org.python.core.PyObject; import org.python.core.PyString; import org.python.core.PyTuple; -import org.python.core.__builtin__; import org.python.core.Untraversable; +import org.python.core.__builtin__; +import org.python.modules._locale.DateSymbolLocale; +import org.python.modules._locale._locale; + @Untraversable class TimeFunctions extends PyBuiltinFunctionSet @@ -226,12 +227,15 @@ private static int item(PyTuple tup, int i) { } private static GregorianCalendar _tupletocal(PyTuple tup) { - return new GregorianCalendar(item(tup, 0), - item(tup, 1), - item(tup, 2), - item(tup, 3), - item(tup, 4), - item(tup, 5)); + GregorianCalendar gc = new GregorianCalendar(item(tup, 0), + item(tup, 1), + item(tup, 2), + item(tup, 3), + item(tup, 4), + item(tup, 5)); + + gc.setGregorianChange(new Date(Long.MIN_VALUE)); + return gc; } public static double mktime(PyTuple tup) { @@ -254,6 +258,8 @@ public static double mktime(PyTuple tup) { protected static PyTimeTuple _timefields(double secs, TimeZone tz) { GregorianCalendar cal = new GregorianCalendar(tz); cal.clear(); + cal.setGregorianChange(new Date(Long.MIN_VALUE)); + secs = secs * 1000; if (secs < Long.MIN_VALUE || secs > Long.MAX_VALUE) { throw Py.ValueError("timestamp out of range for platform time_t"); @@ -324,11 +330,11 @@ public static PyString ctime(PyObject secs) { } // Python's time module specifies use of current locale - protected static Locale currentLocale = null; - protected static DateFormatSymbols datesyms = new DateFormatSymbols(); + protected static DateSymbolLocale datesyms = _locale.getDateSymbolLocale(); protected static String[] shortdays = null; protected static String[] shortmonths = null; + // Consider moving to CEmulationLocale, where there is another copy private static String[] enshortdays = new String[] {"Mon", "Tue", "Wed", @@ -370,7 +376,7 @@ private synchronized static String _shortday(int dow) { } private synchronized static String _shortmonth(int month0to11) { - // getShortWeekdays() returns a 13 element array with the last item + // getShortMonths() returns a 13 element array with the last item // being the empty string. This is also undocumented ;-/ if (shortmonths == null) { shortmonths = new String[12]; @@ -628,13 +634,16 @@ else if (12 <= j && j < 24) // locale is set by user.language and user.region // properties and is "en_US" by default, at least around // here! Locale "en_US" differs from locale "C" in the way - // it represents dates and times. Eventually we might want - // to craft a "C" locale for Java and set Jython to use - // this by default, but that's too much work right now. + // it represents dates and times. Beta support for a "C" + // locale is in org.python.modules._locale.CEmulationLocale // - // For now, we hard code %x and %X to return values - // formatted in the "C" locale, i.e. the default way - // CPython does it. E.g.: + // For now, we continue the historically hard coded pre-2.7.1 + // %x and %X behaviour to return values formatted in the + // "C" locale, i.e. the default way CPython does it. This + // can be unified and simplified using CEmulationLocale once + // native _locale support becomes the default in a future + // version. + // E.g.: // %x == mm/dd/yy // %X == HH:mm:SS // @@ -693,9 +702,9 @@ else if (12 <= j && j < 24) private static void checkLocale() { - if (!Locale.getDefault().equals(currentLocale)) { - currentLocale = Locale.getDefault(); - datesyms = new DateFormatSymbols(currentLocale); + DateSymbolLocale latestLocale = _locale.getDateSymbolLocale(); + if (!latestLocale.equals(datesyms)) { + datesyms = latestLocale; shortdays = null; shortmonths = null; } @@ -705,10 +714,6 @@ public static PyTuple strptime(String data_string) { return strptime(data_string, DEFAULT_FORMAT_PY); } - /** - * Calls _strptime.strptime(), for cases that our SimpleDateFormat backed - * strptime can't handle. - */ private static PyTuple pystrptime(String data_string, String format) { return (PyTuple) __builtin__.__import__("_strptime") .invoke("_strptime_time", @@ -723,3 +728,4 @@ public static PyTuple strptime(String data_string, String format) { private static final String DEFAULT_FORMAT_PY = "%a %b %d %H:%M:%S %Y"; } + diff --git a/src/org/python/modules/ucnhash.dat b/src/org/python/modules/ucnhash.dat index 2fd71d474..fd3d76729 100644 Binary files a/src/org/python/modules/ucnhash.dat and b/src/org/python/modules/ucnhash.dat differ diff --git a/src/org/python/modules/ucnhash.java b/src/org/python/modules/ucnhash.java index 7ae58a4c3..e54078fd1 100644 --- a/src/org/python/modules/ucnhash.java +++ b/src/org/python/modules/ucnhash.java @@ -1,10 +1,14 @@ -// Copyright 1998 Finn Bock. - +/* Copyright 1998 Finn Bock. + * Updated 2017 by Stefan Richthofer to support Unicode 9.0 + */ package org.python.modules; -import java.io.*; -import org.python.core.*; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.BufferedInputStream; +import java.io.IOException; +import org.python.core.ucnhashAPI; public class ucnhash implements ucnhashAPI { @@ -12,7 +16,6 @@ public class ucnhash implements ucnhashAPI { private static int n; private static int m; private static int minchar; - private static int maxchar; private static int alphasz; private static int maxlen; private static int maxidx; @@ -34,12 +37,10 @@ public class ucnhash implements ucnhashAPI { // The raw data and indexes into start of each name // The rawindex is sorted based on the wordindexes. private static byte[] rawdata; - private static char[] rawindex; + private static int[] rawindex; // The mapping from raw data index to unicode code points. - private static char[] codepoint; - - + private static int[] codepoint; public static String[] __depends__ = new String[] { @@ -48,23 +49,26 @@ public class ucnhash implements ucnhashAPI { public static void loadTables() throws Exception { - InputStream instream = ucnhash.class. - getResourceAsStream("ucnhash.dat"); + InputStream instream = + ucnhash.class.getResourceAsStream("ucnhash.dat"); if (instream == null) - throw new IOException("Unicode name database not found: " + - "ucnhash.dat"); + throw new IOException( + "Unicode name database not found: ucnhash.dat"); - DataInputStream in = new DataInputStream( - new BufferedInputStream(instream)); + DataInputStream in = + new DataInputStream(new BufferedInputStream(instream)); n = in.readShort(); m = in.readShort(); - minchar= in.readShort(); - maxchar = in.readShort(); + minchar = in.readShort(); alphasz = in.readShort(); maxlen = in.readShort(); maxidx = maxlen*alphasz-minchar; - + /* + if (debug) { + System.out.println("n "+n+" m "+m+" maxlen "+maxlen+ + " minchar "+minchar+" alphasz "+alphasz); + } */ G = readShortTable(in); if (in.readShort() != 3) throw new IOException("UnicodeNameMap file corrupt, " + @@ -76,24 +80,41 @@ public static void loadTables() throws Exception { wordoffs = readShortTable(in); worddata = readByteTable(in); + /* + if (debug) { + System.out.println("G "+G.length+" T0 "+T0.length+ + " T1 "+T1.length+" T2 "+T2.length); + System.out.println("wordoffs: "+wordoffs.length+ + " worddata: "+worddata.length); + }*/ wordstart = in.readShort(); wordcutoff = in.readShort(); maxklen = in.readShort(); rawdata = readByteTable(in); - rawindex = readCharTable(in); - codepoint = readCharTable(in); + // Formerly rawindex and codepoint were 16 bit + //rawindex = readCharTable(in); + //codepoint = readCharTable(in); + rawindex = readIntTable(in); + codepoint = readIntTable(in); + /* + if (debug) { + System.out.println("wordstart: "+wordstart+ + " wordcutoff: "+wordcutoff+" maxklen: "+maxklen); + System.out.println("rawdata: "+rawdata.length); + System.out.println("rawindex: "+rawindex.length+ + " codepoint: "+codepoint.length); + }*/ } - private static short[] readShortTable(DataInputStream in) - throws IOException + throws IOException { - if (in.read() != 't') + if (in.read() != 't') { throw new IOException("UnicodeNameMap file corrupt, shorttable"); - - int n = in.readUnsignedShort() / 2; + } + int n = in.readInt() / 2; short[] table = new short[n]; for (int i = 0; i < n; i++) { table[i] = in.readShort(); @@ -101,13 +122,27 @@ private static short[] readShortTable(DataInputStream in) return table; } + private static int[] readIntTable(DataInputStream in) + throws IOException + { + if (in.read() != 't') { + throw new IOException("UnicodeNameMap file corrupt, inttable"); + } + int n = in.readInt() / 4; + int[] table = new int[n]; + for (int i = 0; i < n; i++) { + table[i] = in.readInt(); + } + return table; + } + private static char[] readCharTable(DataInputStream in) - throws IOException + throws IOException { - if (in.read() != 't') + if (in.read() != 't') { throw new IOException("UnicodeNameMap file corrupt, chartable"); - - int n = in.readUnsignedShort() / 2; + } + int n = in.readInt() / 2; char[] table = new char[n]; for (int i = 0; i < n; i++) { table[i] = in.readChar(); @@ -116,17 +151,17 @@ private static char[] readCharTable(DataInputStream in) } private static byte[] readByteTable(DataInputStream in) - throws IOException + throws IOException { - if (in.read() != 't') + if (in.read() != 't') { throw new IOException("UnicodeNameMap file corrupt, byte table"); - int n = in.readUnsignedShort(); + } + int n = in.readInt(); byte[] table = new byte[n]; in.readFully(table); return table; } - public static int hash(String key) { return hash(key, 0, key.length()); } @@ -154,84 +189,80 @@ public static int hash(String key, int start, int end) { return (G[f0] + G[f1] + G[f2]) % m; } - private static final char[] charmap = - " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-".toCharArray(); + " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()".toCharArray(); private static String getWord(int idx) { - int offset = wordoffs[idx]; - int end = worddata.length; - if (idx < wordoffs.length-1) - end = wordoffs[idx+1]; - StringBuilder buf = new StringBuilder(); - for (int i = offset; i < end; i++) - buf.append(charmap[worddata[i]]); - return buf.toString(); + int offset = wordoffs[idx]; + int end = worddata.length; + if (idx < wordoffs.length-1) + end = wordoffs[idx+1]; + StringBuilder buf = new StringBuilder(); + for (int i = offset; i < end; i++) + buf.append(charmap[worddata[i]]); + return buf.toString(); } - private static boolean match(int idx, byte[] raw, int begin, int end) { - int woff = wordoffs[idx]; - int wend = worddata.length; - if (idx < wordoffs.length-1) - wend = wordoffs[idx+1]; - - if (end-begin != wend - woff) - return false; - int l = end-begin; - for (int i = 0; i < l; i++) { - if (worddata[woff + i] != raw[begin + i]) - return false; - } - return true; + int woff = wordoffs[idx]; + int wend = worddata.length; + if (idx < wordoffs.length-1) { + wend = wordoffs[idx+1]; + } + if (end-begin != wend - woff) { + return false; + } + int l = end-begin; + for (int i = 0; i < l; i++) { + if (worddata[woff + i] != raw[begin + i]) { + return false; + } + } + return true; } - - private static int compare(byte[] a1, int off1, int len1, byte[] a2, int off2, int len2) { for (int i = 0; i < len1 && i < len2; i++) { int d = (a1[off1 + i] & 0xFF) - (a2[off2 + i] & 0xFF); - if (d != 0) + if (d != 0) { return d; + } } return len1 - len2; } + // Was formerly 5, before rawindex changed to 32 bit: + private static final int raw_block = 3; private static int binarysearch(byte[] rawlist, int start, int end) { int floor = 0; - int ceiling = (rawindex.length) / 5; - + int ceiling = (rawindex.length) / raw_block; + int middle, off, len, d; while (floor < ceiling - 1) { - int middle = (floor + ceiling) / 2; - if (debug) - System.out.println("floor:" + floor + " ceiling:" + - ceiling +" => " + middle); - - int off = rawindex[middle*5]; - int len = rawindex[middle*5+4] & 0x1F; - int d = compare(rawlist, start, end - start, rawdata, off, len); - if (d < 0) - ceiling = middle; - else if (d > 0) - floor = middle; - else - return middle * 12; + middle = (floor + ceiling) / 2; + /*if (debug) + System.out.println("floor:" + floor + " ceiling:" + + ceiling +" => " + middle); */ + off = rawindex[middle*raw_block]; + len = rawindex[middle*raw_block+raw_block-1] & 0x1F; + d = compare(rawlist, start, end - start, rawdata, off, len); + if (d < 0) + ceiling = middle; + else if (d > 0) + floor = middle; + else + return middle * 12; } - int tmp = floor*5; - - int off = rawindex[tmp++]; - long lengths = ((long) rawindex[tmp++] << 48) | - ((long) rawindex[tmp++] << 32) | - ((long) rawindex[tmp++] << 16) | - rawindex[tmp++]; - + int tmp = floor*raw_block; + off = rawindex[tmp++]; + long lengths = (long) rawindex[tmp++] << 32 | + rawindex[tmp++] & 0xFFFFFFFFL; floor *= 12; for (int i = 0; i < 12; i++) { - int len = (int) (lengths >> (i * 5)) & 0x1F; + len = (int) (lengths >> (i * 5)) & 0x1F; if (compare(rawlist, start, end, rawdata, off, len) == 0) return floor; off += len; @@ -244,37 +275,109 @@ public static int lookup(String name) { return lookup(name, 0, name.length()); } - private static int lookup(String name, int start, int end) { - byte[] rawlist = new byte[32]; int ridx = 0; int rbegin = 0; int rstart = 0; - int i; + int i, begin; char ch; byte v; while (true) { rbegin = ridx; - int begin = start; - for (i = start; i < end; i++) { - char ch = name.charAt(i); + begin = start; +lfor: for (i = start; i < end; i++) { + ch = name.charAt(i); + /* if (ch == ' ') { start = i+1; break; } - int v; if (ch >= 'a' && ch <= 'z') ch = (char) (ch - 'a' + 'A'); if (ch >= 'A' && ch <= 'Z') v = ch - 'A' + 1; else if (ch >= '0' && ch <= '9') v = ch - '0' + 27; - else if (ch == '-') - v = 37; - else - return -1; + else { + switch (ch) { + case '-': v = 37; break; + case '(': v = 38; break; + case ')': v = 39; break; + default: return -1; + } + } */ // Unfold this logic into one switch: + // (generated by printCharCases(), see below) + switch (ch) { + case ' ': start = i+1; break lfor; + case 'a': v = 1; break; + case 'b': v = 2; break; + case 'c': v = 3; break; + case 'd': v = 4; break; + case 'e': v = 5; break; + case 'f': v = 6; break; + case 'g': v = 7; break; + case 'h': v = 8; break; + case 'i': v = 9; break; + case 'j': v = 10; break; + case 'k': v = 11; break; + case 'l': v = 12; break; + case 'm': v = 13; break; + case 'n': v = 14; break; + case 'o': v = 15; break; + case 'p': v = 16; break; + case 'q': v = 17; break; + case 'r': v = 18; break; + case 's': v = 19; break; + case 't': v = 20; break; + case 'u': v = 21; break; + case 'v': v = 22; break; + case 'w': v = 23; break; + case 'x': v = 24; break; + case 'y': v = 25; break; + case 'z': v = 26; break; + case 'A': v = 1; break; + case 'B': v = 2; break; + case 'C': v = 3; break; + case 'D': v = 4; break; + case 'E': v = 5; break; + case 'F': v = 6; break; + case 'G': v = 7; break; + case 'H': v = 8; break; + case 'I': v = 9; break; + case 'J': v = 10; break; + case 'K': v = 11; break; + case 'L': v = 12; break; + case 'M': v = 13; break; + case 'N': v = 14; break; + case 'O': v = 15; break; + case 'P': v = 16; break; + case 'Q': v = 17; break; + case 'R': v = 18; break; + case 'S': v = 19; break; + case 'T': v = 20; break; + case 'U': v = 21; break; + case 'V': v = 22; break; + case 'W': v = 23; break; + case 'X': v = 24; break; + case 'Y': v = 25; break; + case 'Z': v = 26; break; + case '0': v = 27; break; + case '1': v = 28; break; + case '2': v = 29; break; + case '3': v = 30; break; + case '4': v = 31; break; + case '5': v = 32; break; + case '6': v = 33; break; + case '7': v = 34; break; + case '8': v = 35; break; + case '9': v = 36; break; + case '-': v = 37; break; + case '(': v = 38; break; + case ')': v = 39; break; + default: return -1; + } - rawlist[ridx++] = (byte) v; + rawlist[ridx++] = v; if (ch == '-' && start != i) { start = ++i; break; @@ -282,55 +385,71 @@ else if (ch == '-') } int hash = hash(name, begin, i); + /* + We skip this try for now, because the issue doesn't occur + with Unicode 9.0 ucnhash.dat bundled with Jython. + Anyway, this might point to some subtle bug. + Todo: Investigate + + int hash; + // Currently needed if with older Unicode a + // name containing '(' or ')' is searched: + try { + hash = hash(name, begin, i); + } catch (ArrayIndexOutOfBoundsException aexc) { + return -1; + } + */ - if (debug) - System.out.println(name.substring(begin, i) + " " + hash); - - boolean isWord = hash >= 0 && - ridx - rbegin > 1 && - match(hash, rawlist, rbegin, ridx); + // if (debug) System.out.println(name.substring(begin, i) + " " + hash); - if (isWord) { - if (debug) - System.out.println("match " + getWord(hash)); + if (hash >= 0 && ridx - rbegin > 1 && + match(hash, rawlist, rbegin, ridx)) { + // if (debug) System.out.println("match " + getWord(hash)); hash += wordstart; ridx = rstart; if (hash > wordcutoff) { rawlist[ridx++] = (byte) ((hash >> 8) + wordcutoff); rawlist[ridx++] = (byte) (hash & 0xFF); - } else - rawlist[ridx++] = (byte) hash; - } - rstart = ridx; - - if (i >= end) - break; - - if (!isWord) { + } else { + rawlist[ridx++] = (byte) hash; + } + rstart = ridx; + if (i >= end) { + break; + } + } else { + rstart = ridx; + if (i >= end) { + break; + } rawlist[ridx++] = 0; } - } + /* if (debug) { System.out.print("rawdata: "); for (int k = 0; k < ridx; k++) System.out.print((rawlist[k] & 0xFF) + " "); System.out.println(); - } + } */ int idx = binarysearch(rawlist, 0, ridx); - if (idx < 0) + if (idx < 0) { return idx; + } + + /* if (debug) { System.out.println("idx:" + idx); System.out.println("codepoint:" + codepoint[idx] + " " + Integer.toHexString(codepoint[idx])); - } + } */ + return codepoint[idx]; } - // From the ucnhashAPI interface public int getCchMax() { if (!initialized()) @@ -339,25 +458,24 @@ public int getCchMax() { } - private static String cjkPrefix = "CJK COMPATIBILITY IDEOGRAPH-"; private static int cjkPrefixLen = cjkPrefix.length(); // From the ucnhashAPI interface public int getValue(String s, int start, int end) { - if (!initialized()) + if (!initialized()) { return -1; + } if (s.regionMatches(start, cjkPrefix, 0, cjkPrefixLen)) { try { - String hex = s.substring(start + cjkPrefixLen, end); - int v = Integer.parseInt(hex, 16); - return v; + String hex = s.substring(start + cjkPrefixLen, end); + int v = Integer.parseInt(hex, 16); + return v; } catch (NumberFormatException exc) { - return -1; // Maybe fallthrough to the main algorithme. + return -1; // Maybe fall through to the main algorithm. } } - return lookup(s, start, end); } @@ -365,12 +483,10 @@ public int getValue(String s, int start, int end) { private static boolean initialized = false; private static boolean loaded = false; - private synchronized boolean initialized() { - if (initialized && loaded) - return true; - if (initialized) - return false; + if (initialized) { + return loaded; + } try { loadTables(); loaded = true; @@ -381,38 +497,66 @@ private synchronized boolean initialized() { return true; } - private static boolean debug = false; + /* + public static int lookupChar(char ch) { + int v; + if (ch >= 'a' && ch <= 'z') + ch = (char) (ch - 'a' + 'A'); + if (ch >= 'A' && ch <= 'Z') + v = ch - 'A' + 1; + else if (ch >= '0' && ch <= '9') + v = ch - '0' + 27; + else { + switch (ch) { + case '-': v = 37; break; + case '(': v = 38; break; + case ')': v = 39; break; + default: return -1; + } + } + return v; + } + + public static void printCharCases() { + char[] charmapFull = + " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-()" + .toCharArray(); + for (char ch: charmapFull) { + System.out.println("case \'"+ch+"\': v = "+lookupChar(ch)+"; break;"); + } + } */ + /* + private static boolean debug = false; public static void main(String[] args) throws Exception { - loadTables(); - - debug = true; - -/* - System.out.println(getWord(hash("ARABIC"))); - System.out.println(getWord(hash("SMALL"))); - System.out.println(getWord(hash("YI"))); - System.out.println(getWord(hash("SYLLABLE"))); - System.out.println(getWord(hash("WITH"))); - System.out.println(getWord(hash("LETTER"))); - - System.out.println(lookup("NULL")); - System.out.println(lookup("LATIN CAPITAL LETTER AFRICAN D")); - System.out.println(lookup("GURMUKHI TIPPI")); - System.out.println(lookup("TIBETAN MARK GTER YIG MGO -UM " + - "RNAM BCAD MA")); - System.out.println(lookup("HANGUL CHOSEONG PIEUP")); - System.out.println(lookup("SINGLE LOW-9 QUOTATION MARK")); -*/ - - System.out.println(lookup("BACKSPACE")); -// System.out.println(lookup("ACTIVATE SYMMETRIC SWAPPING")); - -/* - System.out.println(lookup("LATIN CAPITAL LETTER A")); - System.out.println(lookup("GREATER-THAN SIGN")); - System.out.println(lookup("EURO-CURRENCY SIGN")); -*/ - } + loadTables(); + + debug = true; + + System.out.println(getWord(hash("ARABIC"))); + System.out.println(getWord(hash("SMALL"))); + System.out.println(getWord(hash("YI"))); + System.out.println(getWord(hash("SYLLABLE"))); + System.out.println(getWord(hash("WITH"))); + System.out.println(getWord(hash("LETTER"))); + + System.out.println(lookup("NULL")); // 0 + System.out.println(lookup("LATIN CAPITAL LETTER AFRICAN D")); // 393 + System.out.println(lookup("DOUBLE-STRUCK ITALIC SMALL D")); // 8518 + System.out.println(lookup("GURMUKHI TIPPI")); // 2672 + System.out.println(lookup("TIBETAN MARK GTER YIG MGO -UM" + + " RNAM BCAD MA")); // 3842 + System.out.println(lookup("HANGUL CHOSEONG PIEUP")); // 4359 + System.out.println(lookup("SINGLE LOW-9 QUOTATION MARK")); // 8218 + + System.out.println(lookup("BACKSPACE")); // 8 + System.out.println(lookup("ACTIVATE SYMMETRIC SWAPPING")); // 8299 + + System.out.println(lookup("LATIN CAPITAL LETTER A")); // 65 + System.out.println(lookup("GREATER-THAN SIGN")); // 62 + System.out.println(lookup("EURO-CURRENCY SIGN")); // 8352 + System.out.println(lookup("FORM FEED (FF)")); // 12 + System.out.println(lookup("FORM FEED (F")); // -1 + } */ } diff --git a/src/org/python/modules/zipimport/zipimporter.java b/src/org/python/modules/zipimport/zipimporter.java index 4443a8181..675341363 100644 --- a/src/org/python/modules/zipimport/zipimporter.java +++ b/src/org/python/modules/zipimport/zipimporter.java @@ -6,6 +6,8 @@ import java.io.InputStream; import java.util.Date; import java.util.Enumeration; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -20,8 +22,10 @@ import org.python.core.PySystemState; import org.python.core.PyTuple; import org.python.core.PyType; +import org.python.core.PyUnicode; import org.python.core.Traverseproc; import org.python.core.Visitproc; +import org.python.core.imp; import org.python.core.util.FileUtil; import org.python.core.util.StringUtil; import org.python.core.util.importer; @@ -48,10 +52,17 @@ public class zipimporter extends importer implements Traverseproc { "a zipfile. ZipImportError is raised if 'archivepath' doesn't point to\n" + "a valid Zip archive."); - /** Pathname of the Zip archive */ - @ExposedGet + private static Logger log = Logger.getLogger("org.python.import"); + + /** Path to the Zip archive */ public String archive; + /** Path to the Zip archive as FS-encoded str. */ + @ExposedGet(name = "archive") + public PyString getArchive() { + return Py.fileSystemEncode(archive); + } + /** File prefix: "a/sub/directory/" */ @ExposedGet public String prefix; @@ -80,7 +91,7 @@ public zipimporter(String path) { @ExposedMethod final void zipimporter___init__(PyObject[] args, String[] kwds) { ArgParser ap = new ArgParser("__init__", args, kwds, new String[] {"path"}); - String path = ap.getString(0); + String path = imp.fileSystemDecode(ap.getPyObject(0)); zipimporter___init__(path); } @@ -113,10 +124,11 @@ private void zipimporter___init__(String path) { pathFile = parentFile; } if (archive != null) { - files = zipimport._zip_directory_cache.__finditem__(archive); + PyUnicode archivePath = Py.newUnicode(archive); + files = zipimport._zip_directory_cache.__finditem__(archivePath); if (files == null) { files = readDirectory(archive); - zipimport._zip_directory_cache.__setitem__(archive, files); + zipimport._zip_directory_cache.__setitem__(archivePath, files); } } else { throw zipimport.ZipImportError("not a Zip file: " + path); @@ -172,11 +184,12 @@ final PyObject zipimporter_load_module(String fullname) { */ @Override public String get_data(String path) { - return zipimporter_get_data(path); + return zipimporter_get_data(Py.newUnicode(path)); } @ExposedMethod - final String zipimporter_get_data(String path) { + final String zipimporter_get_data(PyObject opath) { + String path = Py.fileSystemDecode(opath); int len = archive.length(); if (len < path.length() && path.startsWith(archive + File.separator)) { path = path.substring(len + 1); @@ -246,7 +259,8 @@ public PyObject get_filename(String fullname) { final PyObject zipimporter_get_filename(String fullname) { ModuleCodeData moduleCodeData = getModuleCode(fullname); if (moduleCodeData != null) { - return new PyString(moduleCodeData.path); + // File names generally expected in the FS encoding at the Python level + return Py.fileSystemEncode(moduleCodeData.path); } return Py.None; } @@ -306,7 +320,7 @@ public ZipBundle makeBundle(String datapath, PyObject entry) { try { return new ZipBundle(zipArchive, zipArchive.getInputStream(dataEntry)); } catch (IOException ioe) { - Py.writeDebug("import", "zipimporter.getDataStream exception: " + ioe.toString()); + log.log(Level.FINE, "zipimporter.getDataStream exception: {0}", ioe.toString()); throw zipimport.ZipImportError("zipimport: can not open file: " + archive); } } @@ -397,7 +411,8 @@ private void readZipFile(ZipFile zipFile, PyObject files) { ZipEntry zipEntry = zipEntries.nextElement(); String name = zipEntry.getName().replace('/', File.separatorChar); - PyObject __file__ = new PyString(archive + File.separator + name); + // File names generally expected in the FS encoding at the Python level + PyObject __file__ = Py.fileSystemEncode(archive + File.separator + name); PyObject compress = Py.newInteger(zipEntry.getMethod()); PyObject data_size = new PyLong(zipEntry.getCompressedSize()); PyObject file_size = new PyLong(zipEntry.getSize()); @@ -411,7 +426,7 @@ private void readZipFile(ZipFile zipFile, PyObject files) { PyTuple entry = new PyTuple(__file__, compress, data_size, file_size, file_offset, time, date, crc); - files.__setitem__(new PyString(name), entry); + files.__setitem__(Py.newStringOrUnicode(name), entry); } } @@ -511,12 +526,13 @@ public String toString() { @ExposedMethod(names = "__repr__") final String zipimporter_toString() { - String displayArchive = archive != null ? archive : "???"; + // __repr__ has to return bytes not unicode + String bytesName = archive != null ? Py.fileSystemEncode(archive).getString() : "???"; if (prefix != null && !"".equals(prefix)) { - return String.format("", - displayArchive, File.separatorChar, prefix); + return String.format("", bytesName, + File.separatorChar, prefix); } - return String.format("", displayArchive); + return String.format("", bytesName); } /** @@ -550,12 +566,12 @@ public void close() { /* Traverseproc implementation */ @Override public int traverse(Visitproc visit, Object arg) { - if (files != null) { - int retVal = visit.visit(files, arg); - if (retVal != 0) { - return retVal; - } - } + if (files != null) { + int retVal = visit.visit(files, arg); + if (retVal != 0) { + return retVal; + } + } return sys == null ? 0 : visit.visit(sys, arg); } diff --git a/src/org/python/modules/zipimport/zipimporterDerived.java b/src/org/python/modules/zipimport/zipimporterDerived.java index 35e9ad83f..35fe1cbd9 100644 --- a/src/org/python/modules/zipimport/zipimporterDerived.java +++ b/src/org/python/modules/zipimport/zipimporterDerived.java @@ -58,7 +58,7 @@ public PyObject getDict() { } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap||newDict instanceof PyDictionary) { + if (newDict instanceof AbstractDict) { dict=newDict; if (dict.__finditem__(PyString.fromInterned("__del__"))!=null&&!JyAttribute.hasAttr(this,JyAttribute.FINALIZE_TRIGGER_ATTR)) { FinalizeTrigger.ensureFinalizer(this); diff --git a/src/org/python/util/Generic.java b/src/org/python/util/Generic.java index 0124cdfe9..55bd542bb 100644 --- a/src/org/python/util/Generic.java +++ b/src/org/python/util/Generic.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; +import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -34,6 +35,14 @@ public static List list() { return new ArrayList(); } + /** + * Makes a List with its generic type inferred from whatever it's being assigned to. + * Sets initial capacity accordingly. + */ + public static List list(int capacity) { + return new ArrayList(capacity); + } + /** * Makes a List with its generic type inferred from whatever it's being assigned to filled with * the items in contents. @@ -54,6 +63,23 @@ public static Map map() { return new HashMap(); } + /** + * Makes an IdentityHashMap using generic types inferred from whatever this is being + * assigned to. + */ + public static Map identityHashMap() { + return new IdentityHashMap(); + } + + /** + * Makes an IdentityHashMap using generic types inferred from whatever this is being + * assigned to. + * Sets initial capacity accordingly. + */ + public static Map identityHashMap(int capacity) { + return new IdentityHashMap(capacity); + } + /** * Makes a ConcurrentMap using generic types inferred from whatever this is being * assigned to. @@ -77,6 +103,14 @@ public static Set linkedHashSet() { return new LinkedHashSet(); } + /** + * Makes a LinkedHashSet using the generic type inferred from whatever this is being assigned to. + * Sets initial capacity accordingly. + */ + public static Set linkedHashSet(int capacity) { + return new LinkedHashSet(capacity); + } + /** * Makes a Set using the generic type inferred from whatever this is being assigned to filled * with the items in contents. diff --git a/src/org/python/util/InteractiveConsole.java b/src/org/python/util/InteractiveConsole.java index 228528805..786442bfe 100644 --- a/src/org/python/util/InteractiveConsole.java +++ b/src/org/python/util/InteractiveConsole.java @@ -22,13 +22,19 @@ // Based on CPython-1.5.2's code module public class InteractiveConsole extends InteractiveInterpreter { - public static final String CONSOLE_FILENAME = ""; + /** + * Note: This field is actually final; don't modify. + *

      + * To work around an issue in javadoc with Java 8 we cannot have it final for now, see + * issue 2539 for details. + */ + public static String CONSOLE_FILENAME = ""; public String filename; /** * Construct an interactive console, which will "run" when {@link #interact()} is called. The - * name of the console (e.g. in error messages) will be {@value #CONSOLE_FILENAME}. + * name of the console (e.g. in error messages) will be {@link #CONSOLE_FILENAME}. */ public InteractiveConsole() { this(null, CONSOLE_FILENAME); @@ -36,7 +42,7 @@ public InteractiveConsole() { /** * Construct an interactive console, which will "run" when {@link #interact()} is called. The - * name of the console (e.g. in error messages) will be {@value #CONSOLE_FILENAME}. + * name of the console (e.g. in error messages) will be {@link #CONSOLE_FILENAME}. * * @param locals dictionary to use, or if null, a new empty one will be created */ @@ -95,13 +101,14 @@ public void interact() { } /** - * Returns the banner to print before the first interaction: "Jython on ". + * Returns the banner to print before the first interaction: + * "{@code Jython on }". * * @return the banner. */ public static String getDefaultBanner() { - return String - .format("Jython %s on %s", PySystemState.version, Py.getSystemState().platform); + return String.format("Jython %s on %s", PySystemState.version, + Py.getSystemState().platform); } /** diff --git a/src/org/python/util/InteractiveInterpreter.java b/src/org/python/util/InteractiveInterpreter.java index 93d654107..cbee19e1b 100644 --- a/src/org/python/util/InteractiveInterpreter.java +++ b/src/org/python/util/InteractiveInterpreter.java @@ -41,7 +41,7 @@ public InteractiveInterpreter(PyObject locals, PySystemState systemState) { /** * Compile and run some source in the interpreter, in the mode {@link CompileMode#single} which - * is used for incremental compilation at the interactive console, known as "". + * is used for incremental compilation at the interactive console, known as {@code }. * * @param source Python code * @return true to indicate a partial statement was entered @@ -65,31 +65,30 @@ public boolean runsource(String source, String filename) { /** * Compile and run some source in the interpreter, according to the {@link CompileMode} given. * This method supports incremental compilation and interpretation through the return value, - * where true signifies that more input is expected in order to complete the Python - * statement. An interpreter can use this to decide whether to use sys.ps1 (" - * >>> ") or sys.ps2 ("... ") to prompt the next line. - * The arguments are the same as the mandatory ones in the Python compile() - * command. + * where {@code true} signifies that more input is expected in order to complete the Python + * statement. An interpreter can use this to decide whether to use {@code sys.ps1} + * ("{@code >>> }") or {@code sys.ps2} ("{@code ... }") to prompt the next line. The arguments + * are the same as the mandatory ones in the Python {@code compile()} command. *

      * One the following can happen: *

        *
      1. The input is incorrect; compilation raised an exception (SyntaxError or OverflowError). A * syntax traceback will be printed by calling {@link #showexception(PyException)}. Return is - * false.
      2. + * {@code false}. * *
      3. The input is incomplete, and more input is required; compilation returned no code. - * Nothing happens. Return is true.
      4. + * Nothing happens. Return is {@code true}. * *
      5. The input is complete; compilation returned a code object. The code is executed by * calling {@link #runcode(PyObject)} (which also handles run-time exceptions, except for - * SystemExit). Return is false.
      6. + * SystemExit). Return is {@code false}. *
      * * @param source Python code * @param filename name with which to label this console input (e.g. in error messages). * @param kind of compilation required: {@link CompileMode#eval}, {@link CompileMode#exec} or * {@link CompileMode#single} - * @return true to indicate a partial statement was provided + * @return {@code true} to indicate a partial statement was provided */ public boolean runsource(String source, String filename, CompileMode kind) { PyObject code; diff --git a/src/org/python/util/JycompileAntTask.java b/src/org/python/util/JycompileAntTask.java index 31c74bd43..17d002df2 100644 --- a/src/org/python/util/JycompileAntTask.java +++ b/src/org/python/util/JycompileAntTask.java @@ -7,6 +7,7 @@ import org.apache.tools.ant.BuildException; import org.python.core.PyException; import org.python.core.PySystemState; +import org.python.core.RegistryKey; import org.python.core.imp; import org.python.modules._py_compile; @@ -26,16 +27,20 @@ public void process(Set toCompile) throws BuildException { log("Compiling 1 file"); } Properties props = new Properties(); - props.setProperty(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); + props.setProperty(RegistryKey.PYTHON_CACHEDIR_SKIP, "true"); PySystemState.initialize(System.getProperties(), props); for (File src : toCompile) { try { String name = _py_compile.getModuleName(src); String compiledFilePath = name.replace('.', '/'); if (src.getName().endsWith("__init__.py")) { - compiledFilePath += "/__init__"; + compiledFilePath += "/__init__.py"; + } else { + compiledFilePath += ".py"; + // so we can apply imp.makeCompiledFilename } - File compiled = new File(destDir, compiledFilePath + "$py.class"); + File compiled = new File(destDir, + imp.makeCompiledFilename(compiledFilePath)); compile(src, compiled, name); } catch (RuntimeException e) { log("Could not compile " + src); @@ -69,6 +74,6 @@ protected String getFrom() { } protected String getTo() { - return "*$py.class"; + return imp.makeCompiledFilename(getFrom()); } } diff --git a/src/org/python/util/OptionScanner.java b/src/org/python/util/OptionScanner.java new file mode 100644 index 000000000..bd266320a --- /dev/null +++ b/src/org/python/util/OptionScanner.java @@ -0,0 +1,208 @@ +package org.python.util; + +/** + * A somewhat general-purpose scanner for command options, based on CPython {@code getopt.c}. + */ +class OptionScanner { + + /** Valid options. ':' means expect an argument following. */ + private final String programOpts; // e.g. in Python "3bBc:dEhiJm:OQ:RsStuUvVW:xX?"; + /** Index in argv of the arg currently being processed (or about to be started). */ + private int argIndex = 0; + /** Character index within the current element of argv (of the next option to process). */ + private int optIndex = 0; + /** Option argument (where present for returned option). */ + private String optarg = null; + /** Error message (after returning {@link #ERROR}. */ + private String message = ""; + /** Original argv passed at reset */ + private String[] args; + /** Return to indicate argument processing is over. */ + static final char DONE = '\uffff'; + /** Return to indicate option was not recognised. */ + static final char ERROR = '\ufffe'; + /** Return to indicate the next argument is a free-standing argument. */ + static final char ARGUMENT = '\ufffd'; + + /** + * Class representing an argument of the long type, where the whole program argument represents + * one option, e.g. "--help" or "-version". Such options must start with a '-'. The client + * supplies an array of {@code LongSpec} objects to the constructor to define the valid cases. + * Long options are recognised before single-letter options are looked for. Note that "-" itself + * is treated as a long option (even though it is quite short), returning + * {@link OptionScanner#ERROR} if not explicitly defined as a {@code LongSpec}. + */ + static class LongSpec { + + final String key; + final char returnValue; + final boolean hasArgument; + + /** + * Define that the long argument should return a given char value in calls to + * {@link OptionScanner#getOption()}, and whether or not an option argument should appear + * following it on the command line. This character value need not be the same as any + * single-character option, and may be {@link OptionScanner#DONE} (typically for the key + * {@code "--"}. + * + * @param key to match + * @param returnValue to return when that matches + * @param hasArgument an argument to the option is expected to follow + */ + public LongSpec(String key, char returnValue, boolean hasArgument) { + this.key = key; + this.returnValue = returnValue; + this.hasArgument = hasArgument; + } + + /** The same as {@code LongSpec(key, returnValue, false)}. */ + public LongSpec(String key, char returnValue) { + this(key, returnValue, false); + } + } + + private final LongSpec[] longSpec; + + /** + * Create the scanner from command-line arguments, and information about the valid options. + * + * @param args command-line arguments (which must not change during scanning) + * @param programOpts the one-letter options (with : indicating an option argument + * @param longSpec table of long options (like --help) + */ + OptionScanner(String[] args, String programOpts, LongSpec[] longSpec) { + this.args = args; + this.programOpts = programOpts; + this.longSpec = longSpec; + } + + /** + * Get the next option (as a character), or return a code designating successful or erroneous + * completion. + * + * @return next option from command line: the actual character or a code. + */ + char getOption() { + message = ""; + String arg; + optarg = null; + + if (argIndex >= args.length) { + // Option processing is complete + return DONE; + } else { + // We are currently processing: + arg = args[argIndex]; + if (optIndex == 0) { + // And we're at the start of it. + if (!arg.startsWith("-") || arg.length() <= 1) { + // Non-option program argument e.g. "-" or file name. Note no ++argIndex. + return ARGUMENT; + } else if (longSpec != null) { + // Test for "whole arg" special cases + for (LongSpec spec : longSpec) { + if (spec.key.equals(arg)) { + if (spec.hasArgument) { + // Argument to option should be in next arg + if (++argIndex < args.length) { + optarg = args[argIndex]; + } else { + // There wasn't a next arg. + return error("Argument expected for the %s option", arg); + } + } + // And the next processing will be in the next arg + ++argIndex; + return spec.returnValue; + } + } + // No match: fall through. + } + // arg is one or more single character options. Continue after the '-'. + optIndex = 1; + } + } + + // We are in arg=argv[argvIndex] at the character to examine is at optIndex. + assert argIndex < args.length; + assert optIndex > 0; + assert optIndex < arg.length(); + + char option = arg.charAt(optIndex++); + if (optIndex >= arg.length()) { + // The option was at the end of the arg, so the next action uses the next arg. + ++argIndex; + optIndex = 0; + } + + // Look up the option character in the list of allowable ones + int ptr; + if ((ptr = programOpts.indexOf(option)) < 0 || option == ':') { + if (arg.length() <= 2) { + return error("Unknown option: -%c", option); + } else { + // Might be unrecognised long arg, or a one letter option in a group. + return error("Unknown option: -%c or '%s'", option, arg); + } + } + + // Is the option marked as expecting an argument? + if (++ptr < programOpts.length() && programOpts.charAt(ptr) == ':') { + /* + * The option's argument is the rest of the current argv[argvIndex][optIndex:]. If the + * option is the last character of arg, argvIndex has already moved on and optIndex==0, + * so this statement is still true, except that argvIndex may have moved beyond the end + * of the array. + */ + if (argIndex < args.length) { + optarg = args[argIndex].substring(optIndex); + // And the next processing will be in the next arg + ++argIndex; + optIndex = 0; + } else { + // We were looking for an argument but there wasn't one. + return error("Argument expected for the -%c option", option); + } + } + + return option; + } + + /** Get the argument of the previously returned option or {@code null} if none. */ + String getOptionArgument() { + return optarg; + } + + /** + * Get a whole argument (not the argument of an option), for use after {@code ARGUMENT} was + * returned. This advances the internal state to the next argument. + */ + String getWholeArgument() { + optIndex = 0; + return args[argIndex++]; + } + + /** + * Peek at a whole argument (not the argument of an option), for use after {@code ARGUMENT} was + * returned. This does not advance the internal state to the next argument. + */ + String peekWholeArgument() { + return args[argIndex]; + } + + /** Number of arguments that remain unprocessed from the original array. */ + int countRemainingArguments() { + return args.length - argIndex; + } + + /** Get the error message (when we previously returned {@link #ERROR}. */ + String getMessage() { + return message; + } + + /** Set the error message as {@code String.format(message, args)} and return {@link #ERROR}. */ + char error(String message, Object... args) { + this.message = String.format(message, args); + return ERROR; + } +} diff --git a/src/org/python/util/ProxyCompiler.java b/src/org/python/util/ProxyCompiler.java index 341e44f4c..5b3197b09 100644 --- a/src/org/python/util/ProxyCompiler.java +++ b/src/org/python/util/ProxyCompiler.java @@ -3,6 +3,7 @@ import java.util.Properties; import org.python.core.PySystemState; +import org.python.core.RegistryKey; public class ProxyCompiler { @@ -17,7 +18,7 @@ public class ProxyCompiler { */ public static void compile(String filename, String destDir) { Properties props = new Properties(System.getProperties()); - props.setProperty(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); + props.setProperty(RegistryKey.PYTHON_CACHEDIR_SKIP, "true"); PySystemState.initialize(props, null); PythonInterpreter interp = new PythonInterpreter(); diff --git a/src/org/python/util/PyServlet.java b/src/org/python/util/PyServlet.java index fb0494732..a77f7e65e 100644 --- a/src/org/python/util/PyServlet.java +++ b/src/org/python/util/PyServlet.java @@ -5,6 +5,8 @@ import java.util.Enumeration; import java.util.Map; import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -15,19 +17,20 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; +import org.python.Version; +import org.python.core.PrePy; import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PySystemState; /** * This servlet is used to re-serve Jython servlets. It stores bytecode for Jython servlets and * re-uses it if the underlying .py file has not changed. *

      - * e.g. http://localhost:8080/test/hello.py - *

      + * e.g. {@code http://localhost:8080/test/hello.py}
      + * 
      {@literal
        *
        * from javax.servlet.http import HttpServlet
        * class hello(HttpServlet):
      @@ -40,49 +43,57 @@
        *         print >>out, ""
        *         print >>out, ""
        *         out.close()
      - * 
      + * }
      * * in web.xml for the PyServlet context: - *
      - * <web-app>
      - *     <servlet>
      - *         <servlet-name>PyServlet</servlet-name>
      - *         <servlet-class>org.python.util.PyServlet</servlet-class>
      - *         <init-param>
      - *             <param-name>python.home</param-name>
      - *             <param-value>/usr/home/jython-2.5</param-value>
      - *         </init-param>
      - *     </servlet>
      - *     <servlet-mapping>
      - *         <servlet-name>PyServlet</servlet-name>
      - *         <url-pattern>*.py</url-pattern>
      - *     </servlet-mapping>
      - * </web-app>
      - *
      - * 
      + *
      {@literal
      + * 
      + *     
      + *         PyServlet
      + *         org.python.util.PyServlet
      + *         
      + *             python.home
      + *             /usr/home/jython-2.5
      + *         
      + *     
      + *     
      + *         PyServlet
      + *         *.py
      + *     
      + * 
      + * }
      */ public class PyServlet extends HttpServlet { + protected static final Logger logger = Logger.getLogger("org.python.servlet"); + public static final String SKIP_INIT_NAME = "skip_jython_initialization"; protected static final String INIT_ATTR = "__jython_initialized__"; @Override public void init() { - Properties props = new Properties(); + logger.log(Level.INFO, "Jython {0} servlet {1}", + new Object[] {Version.PY_VERSION, getServletName()}); + // Config parameters + Properties props = new Properties(); Enumeration e = getInitParameterNames(); while (e.hasMoreElements()) { String name = (String)e.nextElement(); props.put(name, getInitParameter(name)); } + boolean initialize = getServletConfig().getInitParameter(SKIP_INIT_NAME) != null; + if (getServletContext().getAttribute(INIT_ATTR) != null) { if (initialize) { - System.err.println("Jython has already been initialized in this context, not " - + "initializing for " + getServletName() + ". Add " + SKIP_INIT_NAME - + " to as an init param to this servlet's configuration to indicate this " - + "is expected."); + logger.log(Level.WARNING, // + "Jython has already been initialized in this context." + + " Not initializing for ''{0}''." + + " Add {1} as an init param to this servlet''s configuration" + + " to indicate this is expected.", + new Object[] {getServletName(), SKIP_INIT_NAME}); } } else if (initialize) { init(props, getServletContext()); @@ -96,9 +107,11 @@ public void init() { * context, the system state initialization code only runs once. */ protected static void init(Properties props, ServletContext context) { + String rootPath = getRootPath(context); context.setAttribute(INIT_ATTR, true); - Properties baseProps = PySystemState.getBaseProperties(); + Properties baseProps = PrePy.getSystemProperties(); + // Context parameters Enumeration e = context.getInitParameterNames(); while (e.hasMoreElements()) { @@ -109,6 +122,7 @@ protected static void init(Properties props, ServletContext context) { && baseProps.getProperty("python.home") == null) { props.put("python.home", rootPath + "WEB-INF" + File.separator + "lib"); } + PySystemState.initialize(baseProps, props, new String[0]); PySystemState.add_package("javax.servlet"); PySystemState.add_package("javax.servlet.http"); @@ -237,7 +251,7 @@ private static class CacheEntry { public HttpServlet servlet; CacheEntry(HttpServlet servlet, long date) { - this.servlet= servlet; + this.servlet = servlet; this.date = date; } } diff --git a/src/org/python/util/PythonInterpreter.java b/src/org/python/util/PythonInterpreter.java index f64f344ad..2971ee58d 100644 --- a/src/org/python/util/PythonInterpreter.java +++ b/src/org/python/util/PythonInterpreter.java @@ -6,23 +6,22 @@ import java.util.Properties; import org.python.antlr.base.mod; +import org.python.core.CodeFlag; import org.python.core.CompileMode; import org.python.core.CompilerFlags; -import org.python.core.imp; import org.python.core.Options; import org.python.core.ParserFacade; import org.python.core.Py; import org.python.core.PyCode; import org.python.core.PyException; import org.python.core.PyFile; +import org.python.core.PyFileReader; import org.python.core.PyFileWriter; import org.python.core.PyModule; import org.python.core.PyObject; import org.python.core.PyString; -import org.python.core.PyStringMap; import org.python.core.PySystemState; import org.python.core.__builtin__; -import org.python.core.PyFileReader; /** * The PythonInterpreter class is a standard wrapper for a Jython interpreter for embedding in a @@ -96,21 +95,17 @@ public PythonInterpreter(PyObject dict, PySystemState systemState) { protected PythonInterpreter(PyObject dict, PySystemState systemState, boolean useThreadLocalState) { - if (dict == null) { - dict = Py.newStringMap(); - } - globals = dict; - if (systemState == null) { - systemState = Py.getSystemState(); - } - this.systemState = systemState; + globals = dict != null ? dict : Py.newStringMap(); + this.systemState = systemState != null ? systemState : Py.getSystemState(); setSystemState(); this.useThreadLocalState = useThreadLocalState; - if (!useThreadLocalState) { - PyModule module = new PyModule("__main__", dict); - systemState.modules.__setitem__("__main__", module); + PyModule module = new PyModule("__main__", globals); + this.systemState.modules.__setitem__("__main__", module); + + if (Options.Qnew) { + cflags.setFlag(CodeFlag.CO_FUTURE_DIVISION); } Py.importSiteIfSelected(); @@ -161,6 +156,7 @@ public void setIn(java.io.InputStream inStream) { * stream is used in a byte-oriented way (mostly) that depends on the type of file-like object. * The behaviour as implemented is: *
    Byte order and alignment characters
    CharacterByte orderSize and alignment
    @
    {@code @}nativenative
    =
    {@code =}nativestandard
    <
    {@code <}little-endianstandard
    >
    {@code >}big-endianstandard
    !
    {@code !}network (= big-endian)standard
    + * * * * @@ -198,8 +194,8 @@ public void setOut(PyObject outStream) { } /** - * Sets a {@link Writer} to use for the standard output stream, sys.stdout. The - * behaviour as implemented is to output each object o by calling + * Sets a {@link java.io.Writer} to use for the standard output stream, sys.stdout. + * The behaviour as implemented is to output each object o by calling * o.toString() and writing this as UTF-16. * * @param outStream to use as the output stream @@ -229,8 +225,8 @@ public void setErr(PyObject outStream) { } /** - * Sets a {@link Writer} to use for the standard output stream, sys.stdout. The - * behaviour as implemented is to output each object o by calling + * Sets a {@link java.io.Writer} to use for the standard output stream, sys.stdout. + * The behaviour as implemented is to output each object o by calling * o.toString() and writing this as UTF-16. * * @param outStream to use as the error output stream @@ -261,6 +257,11 @@ public PyObject eval(PyObject code) { /** * Executes a string of Python source in the local namespace. + * + * In some environments, such as Windows, Unicode characters in the script will be converted + * into ascii question marks (?). This can be avoided by first compiling the fragment using + * PythonInterpreter.compile(), and using the overridden form of this method which takes a + * PyCode object. Code page declarations are not supported. */ public void exec(String s) { setSystemState(); diff --git a/src/org/python/util/TemplateAntTask.java b/src/org/python/util/TemplateAntTask.java index 6a2d075e6..2ad69c94b 100644 --- a/src/org/python/util/TemplateAntTask.java +++ b/src/org/python/util/TemplateAntTask.java @@ -95,7 +95,7 @@ public void setSrcdir(String in) { * Verbose flag. */ public void setVerbose(String in) { - verbose = (new Boolean(getProject().replaceProperties(in))).booleanValue(); + verbose = (Boolean.valueOf(getProject().replaceProperties(in))).booleanValue(); } /** @@ -107,7 +107,7 @@ public void setVerbose(String in) { * Lazy flag. */ public void setLazy(String in) { - lazy = (new Boolean(getProject().replaceProperties(in))).booleanValue(); + lazy = (Boolean.valueOf(getProject().replaceProperties(in))).booleanValue(); } public void execute() { diff --git a/src/org/python/util/jython.java b/src/org/python/util/jython.java index 3687d6ff6..8ea70cf0b 100644 --- a/src/org/python/util/jython.java +++ b/src/org/python/util/jython.java @@ -6,17 +6,22 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; +import java.io.PrintStream; +import java.util.LinkedList; import java.util.List; import java.util.Properties; +import java.util.logging.ConsoleHandler; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.python.Version; -import org.python.core.CodeFlag; +import org.python.core.BytecodeLoader; import org.python.core.CompileMode; import org.python.core.Options; +import org.python.core.PrePy; import org.python.core.Py; import org.python.core.PyCode; import org.python.core.PyException; @@ -27,25 +32,78 @@ import org.python.core.PyString; import org.python.core.PyStringMap; import org.python.core.PySystemState; +import org.python.core.RegistryKey; import org.python.core.imp; -import org.python.core.util.RelativeFile; -import org.python.modules._systemrestart; -import org.python.modules.posix.PosixModule; -import org.python.modules.thread.thread; public class jython { + /** Exit status: must have {@code OK.ordinal()==0} */ + private enum Status { + OK, ERROR, NOT_RUN, NO_FILE + } + + /** The root of the Jython Logger hierarchy, named "org.python". */ + public static final Logger logger;// = Logger.getLogger("org.python"); + + /** + * The default format for console log messages in the command-line Jython. See + * {@code java.util.logging.SimpleFormatter} for an explanation of the syntax. + *

    + * This format is used in the absence of other logging preferences. Jython tests for definitions + * in the system properties of {@code java.util.logging.config.class}, + * {@code java.util.logging.config.file}, and {@code java.util.logging.SimpleFormatter.format} + * and if none of these is defined, it sets the last of them to this value. + *

    + * You can choose something else, for example to log with millisecond time stamps, launch Jython + * as:

    +     * jython -vv -J-Djava.util.logging.SimpleFormatter.format="[%1$tT.%1$tL] %3$s: (%4$s) %5$s%n"
    +     * 
    Depending on your shell, the argument may need quoting or escaping. + */ + public static final String CONSOLE_LOG_FORMAT = "%3$s %4$s %5$s%n"; + + static { + SecurityException exception = null; + try { + // Jython console messages (-v option) are emitted using SimpleFormatter + configureSimpleFormatter(CONSOLE_LOG_FORMAT); + } catch (SecurityException se) { + // Unable to access the necessary system properties. Give up on custom logging. + exception = se; + } + + // Whether we can configure it or not, we can still _use_ logging. + logger = Logger.getLogger("org.python"); + + if (exception == null) { + try { + // Make our "org.python" logger do its own output and not propagate to root. + setConsoleHandler(logger); + } catch (SecurityException se) { + // This probably means no logging finer than INFO (so none enabled by -v) + exception = se; + } + } + + if (exception != null) { + logger.log(Level.WARNING, "Unable to format console messages: {0}", + exception.getMessage()); + } + } + // An instance of this class will provide the console (python.console) by default. private static final String PYTHON_CONSOLE_CLASS = "org.python.util.JLineConsole"; private static final String COPYRIGHT = "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information."; + /** The message output when reporting command-line errors and when asked for help. */ static final String usageHeader = "usage: jython [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; - private static final String usage = usageHeader - + "Options and arguments:\n" + /** The message additional to {@link #usageHeader} output when asked for help. */ + // @formatter:off + static final String usageBody = + "Options and arguments:\n" // + "(and corresponding environment variables):\n" + "-B : don't write bytecode files on import\n" // + "also PYTHONDONTWRITEBYTECODE=x\n" + @@ -54,10 +112,10 @@ public class jython { + "-Dprop=v : Set the property `prop' to value `v'\n" + "-E : ignore environment variables (such as JYTHONPATH)\n" + "-h : print this help message and exit (also --help)\n" - + "-i : inspect interactively after running script\n" - // + ", (also PYTHONINSPECT=x)\n" - + " and force prompts, even if stdin does not appear to be a terminal\n" - + "-jar jar : program read from __run__.py in jar file\n" + + "-i : inspect interactively after running script; forces a prompt even\n" + + " if stdin does not appear to be a terminal; also PYTHONINSPECT=x\n" + + "-jar jar : program read from __run__.py in jar file. Deprecated: instead,\n" + + " name the archive as the file argument (runs __main__.py).\n" + "-m mod : run library module as a script (terminates option list)\n" // + "-O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n" // + "-OO : remove doc-strings in addition to the -O optimizations\n" @@ -69,7 +127,7 @@ public class jython { + "-u : unbuffered binary stdout and stderr\n" // + "(also PYTHONUNBUFFERED=x)\n" // + " see man page for details on internal buffering relating to '-u'\n" - + "-v : verbose (trace import statements)\n" + + "-v : verbose (emit more \"org.python\" log messages)\n" // + "(also PYTHONVERBOSE=x)\n" + " can be supplied multiple times to increase verbosity\n" + "-V : print the Python version number and exit (also --version)\n" @@ -80,22 +138,83 @@ public class jython { + "- : program read from stdin (default; interactive mode if a tty)\n" + "arg ... : arguments passed to program in sys.argv[1:]\n" + "\n" + "Other environment variables:\n" // - + "JYTHONPATH: '" + File.pathSeparator + + "JYTHONSTARTUP: file executed on interactive startup (no default)\n" + + "JYTHONPATH : '" + File.pathSeparator + "'-separated list of directories prefixed to the default module\n" - + " search path. The result is sys.path.\n" + + " search path. The result is sys.path.\n" + "PYTHONIOENCODING: Encoding[:errors] used for stdin/stdout/stderr."; + // @formatter:on - public static boolean shouldRestart; + /** + * Print a full usage message onto {@code System.out} or a brief usage message onto + * {@code System.err}. + * + * @param status if {@code == 0} full help version on {@code System.out}. + * @return the status given as the argument. + */ + static Status usage(Status status) { + boolean fullHelp = (status == Status.OK); + PrintStream f = fullHelp ? System.out : System.err; + f.printf(usageHeader); + if (fullHelp) { + f.printf(usageBody); + } else { + f.println("Try 'jython -h' for more information."); + } + return status; + } + + /** + * Try to set the format for SimpleFormatter if no other mechanism has been provided, and + * security allows it. Note that the absolute fall-back format is: + * {@code "%1$tb %1$td, %1$tY %1$tl:%1$tM:%1$tS %1$Tp %2$s%n%4$s: %5$s%6$s%n"}, + * defined ultimately in {@code sun.util.logging.LoggingSupport}. + * + * @param format to set for {@code java.util.logging.SimpleFormatter} + * @throws SecurityException if not allowed to read or set necessary properties. + */ + private static void configureSimpleFormatter(String format) throws SecurityException { + final String CLASS_KEY = "java.util.logging.config.class"; + String className = System.getProperty(CLASS_KEY); + if (className == null) { + final String FILE_KEY = "java.util.logging.config.file"; + String fileName = System.getProperty(FILE_KEY); + if (fileName == null) { + final String FORMAT_KEY = "java.util.logging.SimpleFormatter.format"; + String currentFormat = System.getProperty(FORMAT_KEY); + if (currentFormat == null) { + // Note that this sets the format for _all_ console logging + System.setProperty(FORMAT_KEY, format); + } + } + } + } + + /** + * Customise the logger so that it does not propagate to its parent and has its own + * {@code Handler} accepting all messages. The level set on the logger alone therefore controls + * whether messages are emitted to the console. + * + * @param logger to adjust (always "python.org") + * @throws SecurityException if no permission to adjust logging + */ + private static void setConsoleHandler(Logger logger) throws SecurityException { + logger.setUseParentHandlers(false); + Handler handler = new ConsoleHandler(); + handler.setLevel(Level.ALL); + logger.addHandler(handler); + } /** * Runs a JAR file, by executing the code found in the file __run__.py, which should be in the - * root of the JAR archive. Note that the __name__ is set to the base name of the JAR file and - * not to "__main__" (for historic reasons). This method do NOT handle exceptions. the caller - * SHOULD handle any (Py)Exceptions thrown by the code. + * root of the JAR archive. Note that {@code __name__} is set to the base name of the JAR file + * and not to "__main__" (for historical reasons). This method does not handle + * exceptions. the caller should handle any {@code (Py)Exceptions} thrown by the code. * * @param filename The path to the filename to run. + * @return {@code 0} on normal termination (otherwise throws {@code PyException}). */ - public static void runJar(String filename) { + public static int runJar(String filename) { // TBD: this is kind of gross because a local called `zipfile' just magically // shows up in the module's globals. Either `zipfile' should be called // `__zipfile__' or (preferably, IMO), __run__.py should be imported and a main() @@ -103,371 +222,468 @@ public static void runJar(String filename) { // argument. // // Probably have to keep this code around for backwards compatibility (?) - try { - ZipFile zip = new ZipFile(filename); + try (ZipFile zip = new ZipFile(filename)) { ZipEntry runit = zip.getEntry("__run__.py"); if (runit == null) { - throw Py.ValueError("jar file missing '__run__.py'"); + throw Py.ValueError("can't find '__run__.py' in '" + filename + "'"); } - PyStringMap locals = Py.newStringMap(); - - // Stripping the stuff before the last File.separator fixes Bug #931129 by - // keeping illegal characters out of the generated proxy class name - int beginIndex; - if ((beginIndex = filename.lastIndexOf(File.separator)) != -1) { + /* + * Stripping the stuff before the last File.separator fixes Bug #931129 by keeping + * illegal characters out of the generated proxy class name. Mostly. + */ + int beginIndex = filename.lastIndexOf(File.separator); + if (beginIndex >= 0) { filename = filename.substring(beginIndex + 1); } - locals.__setitem__("__name__", new PyString(filename)); + PyStringMap locals = Py.newStringMap(); + locals.__setitem__("__name__", Py.fileSystemEncode(filename)); locals.__setitem__("zipfile", Py.java2py(zip)); - InputStream file = zip.getInputStream(runit); - PyCode code; - try { - code = Py.compile(file, "__run__", CompileMode.exec); - } finally { - file.close(); - } + InputStream file = zip.getInputStream(runit); // closed when zip is closed + + PyCode code = Py.compile(file, "__run__", CompileMode.exec); Py.runCode(code, locals, locals); + } catch (IOException e) { throw Py.IOError(e); } - } - public static void main(String[] args) { - do { - shouldRestart = false; - run(args); - } while (shouldRestart); + return Status.OK.ordinal(); } - private static List warnOptionsFromEnv() { - ArrayList opts = new ArrayList(); + /** Now equivalent to {@link #main(String[])}, which is to be preferred. */ + @Deprecated + public static void run(String[] args) { + main(args); + } - try { - String envVar = System.getenv("PYTHONWARNINGS"); - if (envVar == null) { - return opts; - } + /** Exit Jython with status (converted to an integer). */ + private static void exit(Status status) { + System.exit(status.ordinal()); + } - for (String opt : envVar.split(",")) { - opt = opt.trim(); - if (opt.length() == 0) { - continue; - } - opts.add(opt); + /** + * Append options from the environment variable {@code PYTHONWARNINGS}, respecting the -E + * option. + * + * @param opts the list to which the options are appended. + */ + private static void addWarnOptionsFromEnv(PyList opts) { + String envVar = getenv("PYTHONWARNINGS", ""); + for (String opt : envVar.split(",")) { + opt = opt.trim(); + if (opt.length() > 0) { + opts.add(Py.fileSystemEncode(opt)); } - } catch (SecurityException e) { - // Continue } + } - return opts; + /** + * Attempt to run a module as the {@code __main__} module, via a call to + * {@code runpy._run_module_as_main}. Exceptions raised by the imported module, including + * {@code SystemExit}, if not handled by {@code runpy} itself, will propagate out of this + * method. Note that if {@code runpy} cannot import the module it calls {@code sys.exit} with a + * message, which will raise {@code SystemExit} from this method. + * + * @param moduleName to run + * @param set_argv0 replace {@code sys.argv[0]} with the file name of the module source + * {@code runpy._run_module_as_main} option. + * @return {@code Status.OK} on normal termination. + */ + private static Status runModule(String moduleName, boolean set_argv0) { + // PEP 338 - Execute module as a script + PyObject runpy = imp.importName("runpy", true); + PyObject runmodule = runpy.__findattr__("_run_module_as_main"); + // May raise SystemExit (with message) + runmodule.__call__(Py.fileSystemEncode(moduleName), Py.newBoolean(set_argv0)); + return Status.OK; } - private static List validWarnActions = Arrays.asList("error", "ignore", "always", - "default", "module", "once"); - - private static void addWarnings(List from, PyList to) { - outerLoop : for (String opt : from) { - String action = opt.split(":")[0]; - for (String validWarnAction : validWarnActions) { - if (validWarnAction.startsWith(action)) { - if (opt.contains(":")) { - to.append(Py.newString(validWarnAction + opt.substring(opt.indexOf(":")))); - } else { - to.append(Py.newString(validWarnAction)); - } - continue outerLoop; - } + /** + * Attempt to treat a file as a source of imports, import a module {@code __main__}, and run it. + * If the file is suitable (e.g. it's a directory or a ZIP archive) the method places the file + * first on {@code sys.path}, so that {@code __main__} and its packaged dependencies may be + * found in it. This permits a zip file containing Python source to be run when given as a first + * argument on the command line. It may be that the file is not of a type that can be imported, + * in which case the return indicates this. + * + * @param archive to run (FS encoded name) + * @return {@code Status.OK} or {@code Status.NOT_RUN} (if the file was not an archive). + */ + private static Status runMainFromImporter(PyString archive) { + PyObject importer = imp.getImporter(archive); + if (!(importer instanceof PyNullImporter)) { + // filename is usable as an import source, so put it in sys.path[0] and import __main__ + Py.getSystemState().path.insert(0, archive); + return runModule("__main__", false); + } + return Status.NOT_RUN; + } + + /** + * Execute the stream {@code fp} as a file, in the given interpreter, as {@code __main__}. The + * file name provided must correspond to the stream. In particular, the file name extension + * "$py.class" will cause the stream to be interpreted as compiled code. For streams that are + * not really files, this name may be a conventional one like {@code ""}, however this + * method will not treat a console stream as interactive. + * + * @param fp Python source code + * @param filename appears FS-encoded in variable {@code __file__} and in error messages + * @param interp to do the work + * @return {@code Status.OK} on normal termination. + */ + // This is roughly equivalent to CPython PyRun_SimpleFileExFlags + private static Status runSimpleFile(InputStream fp, String filename, PythonInterpreter interp) { + + // Reflect the current name in the module's __file__, compare PyRun_SimpleFileExFlags. + final String __file__ = "__file__"; + PyObject globals = interp.globals; + PyObject previousFilename = globals.__finditem__(__file__); + if (previousFilename == null) { + globals.__setitem__(__file__, + // Note that __file__ is widely expected to be encoded bytes + Py.fileSystemEncode(filename)); + } + + // Allow for already-compiled target, but for us it's a $py.class not a .pyc. + if (filename.endsWith("$py.class")) { + // Jython compiled file. + String name = filename.substring(0, filename.length() - 6); // = - ".class" + try { + byte[] codeBytes = imp.readCode(filename, fp, false, imp.NO_MTIME); + File file = new File(filename); + PyCode code = BytecodeLoader.makeCode(name, codeBytes, file.getParent()); + interp.exec(code); + } catch (IOException e) { + throw Py.IOError(e); } - System.err.println(String.format("Invalid -W option ignored: invalid action: '%s'", - action)); + } else { + // Assume Python source file: run in the interpreter + interp.execfile(fp, filename); + } + + // Delete __file__ variable, previously non-existent. Compare PyRun_SimpleFileExFlags. + if (previousFilename == null) { + globals.__delitem__(__file__); } + return Status.OK; } - private static void runModule(InteractiveConsole interp, String moduleName) { - runModule(interp, moduleName, false); + /** + * Execute the stream {@code fp} in the given interpreter. If {@code fp} refers to a stream + * associated with an interactive device (console or terminal input), execute Python source + * statements from the stream in the interpreter as {@code __main__}. Otherwise, the file name + * provided must correspond to the stream, as in + * {@link #runSimpleFile(InputStream, String, PythonInterpreter)}. + * + * @param fp Python source code + * @param filename the name of the file or {@code null} meaning "???" + * @param interp to do the work + * @return {@code Status.OK} on normal termination. + */ + // This is roughly equivalent to CPython PyRun_AnyFileExFlags + private static Status runStream(InputStream fp, String filename, InteractiveConsole interp) { + // Following CPython PyRun_AnyFileExFlags here, blindly, concerning null name. + filename = filename != null ? filename : "???"; + // Run the contents in the interpreter + if (PrePy.isInteractive(fp, filename)) { + // __file__ not defined + interp.interact(null, new PyFile(fp)); + } else { + // __file__ will be defined + runSimpleFile(fp, filename, interp); + } + return Status.OK; } - private static void runModule(InteractiveConsole interp, String moduleName, boolean set_argv0) { - // PEP 338 - Execute module as a script - try { - PyObject runpy = imp.importName("runpy", true); - PyObject runmodule = runpy.__findattr__("_run_module_as_main"); - runmodule.__call__(Py.newStringOrUnicode(moduleName), Py.newBoolean(set_argv0)); - } catch (Throwable t) { - Py.printException(t); - interp.cleanup(); - System.exit(-1); + /** + * Attempt to open the named file and execute it in the interpreter as {@code __main__}, as in + * {@link #runStream(InputStream, String, InteractiveConsole)}. This may raise a Python + * exception, including {@code SystemExit}. If the file cannot be opened, or using it throws a + * Java {@code IOException} that is not converted to a {@code PyException} (i.e. not within the + * executing code), it is reported via {@link #printError(String, Object...)}, and reflected in + * the return status. If the file can be opened, its parent directory will be inserted at + * {@code sys.argv[0]}. + * + * @param filename the name of the file or {@code null} meaning "???" + * @param interp to do the work + * @return {@code Status.OK} on normal termination, {@code Status.NO_FILE} if the file cannot be + * read, or {@code Status.ERROR} on other {@code IOException}s. + */ + private static Status runFile(String filename, InteractiveConsole interp) { + File file = new File(filename); + try (InputStream is = new FileInputStream(file)) { + String parent = file.getAbsoluteFile().getParent(); + interp.getSystemState().path.insert(0, Py.fileSystemEncode(parent)); + // May raise exceptions, (including SystemExit) + return runStream(is, filename, interp); + } catch (FileNotFoundException fnfe) { + // Couldn't open it. No point in going interactive, even if -i given. + printError("can't open file '%s': %s", filename, fnfe); + return Status.NO_FILE; + } catch (IOException ioe) { + // This may happen on the automatically-generated close() + printError("error closing '%s': %s", filename, ioe); + return Status.ERROR; } } - private static boolean runMainFromImporter(InteractiveConsole interp, String filename) { - // Support http://bugs.python.org/issue1739468 - Allow interpreter to execute a zip file or directory - PyString argv0 = Py.newStringOrUnicode(filename); - PyObject importer = imp.getImporter(argv0); - if (!(importer instanceof PyNullImporter)) { - /* argv0 is usable as an import source, so - put it in sys.path[0] and import __main__ */ - Py.getSystemState().path.insert(0, argv0); - runModule(interp, "__main__", true); - return true; + /** + * Attempt to execute the file named in the registry entry {@code python.startup}, which may + * also have been set via the environment variable {@code JYTHONSTARTUP}. This may raise a + * Python exception, including {@code SystemExit} that propagates to the caller. If the file + * cannot be opened, or using it throws a Java {@code IOException} that is not converted to a + * {@code PyException} (i.e. not within the executing code), it is reported via + * {@link #printError(String, Object...)}. + * + * @param interp to do the work + */ + private static void runStartupFile(InteractiveConsole interp) { + String filename = PySystemState.registry.getProperty(RegistryKey.PYTHON_STARTUP, null); + if (filename != null) { + try (InputStream fp = new FileInputStream(filename)) { + // May raise exceptions, (including SystemExit) + // RunStreamOrThrow(fp, filename, interp); + runSimpleFile(fp, filename, interp); + } catch (FileNotFoundException fnfe) { + // Couldn't open it. No point in going interactive, even if -i given. + printError("Could not open startup file '%s'", filename); + } catch (IOException ioe) { + // This may happen on the automatically-generated close() + printError("error closing '%s': %s", filename, ioe); + } } - return false; } - public static void run(String[] args) { + /** + * Main Jython program, following the structure and logic of CPython {@code main.c} to produce + * the same behaviour. The argument to the method is the argument list supplied after the class + * name in the {@code java} command. Arguments up to the executable script name are options for + * Jython; arguments after the executable script are supplied in {@code sys.argv}. "Executable + * script" here means a Python source file name, a module name (following the {@code -m} + * option), a literal command (following the {@code -c} option), or a JAR file name (following + * the {@code -jar} option). As a special case of the file name, "-" is allowed, meaning take + * the script from standard input. + *

    + * The main difference for the caller stems from a difference between C and Java: in C, the + * argument list {@code (argv)} begins with the program name, while in Java all elements of + * {@code (args)} are arguments to the program. + * + * @param args arguments to the program. + */ + public static void main(String[] args) { // Parse the command line options - CommandLineOptions opts = new CommandLineOptions(); - if (!opts.parse(args)) { - if (opts.version) { - System.err.println("Jython " + Version.PY_VERSION); - System.exit(0); - } - if (opts.help) { - System.err.println(usage); - } else if (!opts.runCommand && !opts.runModule) { - System.err.print(usageHeader); - System.err.println("Try `jython -h' for more information."); - } + CommandLineOptions opts = CommandLineOptions.parse(args); - int exitcode = opts.help ? 0 : -1; - System.exit(exitcode); + // Choose the basic action + switch (opts.action) { + case VERSION: + System.err.printf("Jython %s\n", Version.PY_VERSION); + exit(Status.OK); + case HELP: + exit(usage(Status.OK)); + case ERROR: + System.err.println(opts.message); + exit(usage(Status.ERROR)); + case RUN: + // Let's run some Python! ... } + // Adjust relative to the level set by java.util.logging. + PrePy.increaseLoggingLevel(opts.verbosity); + // Get system properties (or empty set if we're prevented from accessing them) - Properties preProperties = PySystemState.getBaseProperties(); + Properties preProperties = PrePy.getSystemProperties(); + addDefaultsFromEnvironment(preProperties); - // Read environment variable PYTHONIOENCODING into properties (registry) - String pythonIoEncoding = getenv("PYTHONIOENCODING"); - if (pythonIoEncoding != null) { - String[] spec = splitString(pythonIoEncoding, ':', 2); - // Note that if encoding or errors is blank (=null), the registry value wins. - addDefault(preProperties, PySystemState.PYTHON_IO_ENCODING, spec[0]); - addDefault(preProperties, PySystemState.PYTHON_IO_ERRORS, spec[1]); + // Treat the apparent filename "-" as no filename + boolean haveDash = "-".equals(opts.filename); + if (haveDash) { + opts.filename = null; } - // Decide if System.in is interactive - if (!opts.fixInteractive || opts.interactive) { - // The options suggest System.in is interactive: but only if isatty() agrees - opts.interactive = Py.isInteractive(); - if (opts.interactive) { + // Sense whether the console is interactive, or we have been told to consider it so. + boolean stdinIsInteractive = PrePy.isInteractive(System.in, null); + + // Shorthand + boolean haveScript = opts.command != null || opts.filename != null || opts.module != null; + + if (Options.inspect || !haveScript) { + // We'll be going interactive eventually. condition an interactive console. + if (PrePy.haveConsole()) { // Set the default console type if nothing else has - addDefault(preProperties, "python.console", PYTHON_CONSOLE_CLASS); + addDefault(preProperties, RegistryKey.PYTHON_CONSOLE, PYTHON_CONSOLE_CLASS); } } - // Setup the basic python system state from these options - PySystemState.initialize(preProperties, opts.properties, opts.argv); - PySystemState systemState = Py.getSystemState(); - - PyList warnoptions = new PyList(); - addWarnings(opts.warnoptions, warnoptions); - if (!Options.ignore_environment) { - addWarnings(warnOptionsFromEnv(), warnoptions); - } - systemState.setWarnoptions(warnoptions); + /* + * Set up the executable-wide state from the options, environment and registry, and create + * the first instance of a sys module. We try to leave to this initialisation the things + * necessary to an embedded interpreter, and to do in the present method only that which + * belongs only to command line application. + * + * (Jython partitions system and interpreter state differently from modern CPython, which is + * able explicitly to create a PyInterpreterState first, after which sys and the thread + * state are created to hang from it.) + */ + // The Jython type system will spring into existence here. This may take a while. + PySystemState.initialize(preProperties, opts.properties); + // Now we can use PyObjects safely. + PySystemState sys = Py.getSystemState(); - // Make sure warnings module is loaded if there are warning options - // Not sure this is needed, but test_warnings.py expects this - if (warnoptions.size() > 0) { + /* + * Jython initialisation does not load the "warnings" module. Rather we defer it to here, + * where we may safely prepare sys.warnoptions from the -W arguments and the contents of + * PYTHONWARNINGS (compare PEP 432). + */ + addFSEncoded(opts.warnoptions, sys.warnoptions); + addWarnOptionsFromEnv(sys.warnoptions); + if (!sys.warnoptions.isEmpty()) { + // The warnings module validates (and may complain about) the warning options. imp.load("warnings"); } - // Now create an interpreter - if (!opts.interactive) { - // Not (really) interactive, so do not use console prompts - systemState.ps1 = systemState.ps2 = Py.EmptyString; - } + /* + * Create the interpreter that we will use as a name space in which to execute the script or + * interactive session. We run site.py as part of interpreter initialisation (as CPython). + */ InteractiveConsole interp = new InteractiveConsole(); - // Print banner and copyright information (or not) - if (opts.interactive && opts.notice && !opts.runModule) { + if (opts.verbosity > 0 || (!haveScript && stdinIsInteractive)) { + // Verbose or going interactive immediately: produce sign on messages. System.err.println(InteractiveConsole.getDefaultBanner()); - } - - if (Py.importSiteIfSelected()) { - if (opts.interactive && opts.notice && !opts.runModule) { + if (Options.importSite) { System.err.println(COPYRIGHT); } } - if (opts.division != null) { - if ("old".equals(opts.division)) { - Options.division_warning = 0; - } else if ("warn".equals(opts.division)) { - Options.division_warning = 1; - } else if ("warnall".equals(opts.division)) { - Options.division_warning = 2; - } else if ("new".equals(opts.division)) { - Options.Qnew = true; - interp.cflags.setFlag(CodeFlag.CO_FUTURE_DIVISION); - } - } + /* + * We currently have sys.argv = PySystemState.defaultArgv = ['']. Python has a special use + * for sys.argv[0] according to the source of the script (-m, -c, etc.), but the rest of it + * comes from the unparsed part of the command line. + */ + addFSEncoded(opts.argv, sys.argv); - // was there a filename on the command line? - if (opts.filename != null) { - if (runMainFromImporter(interp, opts.filename)) { - interp.cleanup(); - return; - } + /* + * At last, we are ready to execute something. This has two parts: execute the script or + * console and (if we didn't execute the console) optionally start an interactive console + * session. The sys.path needs to be prepared in a slightly different way for each case. + */ + Status sts = Status.NOT_RUN; - String path; - try { - path = new File(opts.filename).getCanonicalFile().getParent(); - } catch (IOException ioe) { - path = new File(opts.filename).getAbsoluteFile().getParent(); - } - if (path == null) { - path = ""; - } - Py.getSystemState().path.insert(0, Py.newStringOrUnicode(path)); - if (opts.jar) { - try { + try { + if (opts.command != null) { + // The script is an immediate command -c "..." + sys.argv.set(0, Py.newString("-c")); + sys.path.insert(0, Py.EmptyString); + interp.exec(opts.command); + sts = Status.OK; + + } else if (opts.module != null) { + // The script is a module + sys.argv.set(0, Py.newString("-m")); + sts = runModule(opts.module, true); + + } else if (opts.filename != null) { + // The script is designated by file (or directory) name. + PyString pyFileName = Py.fileSystemEncode(opts.filename); + sys.argv.set(0, pyFileName); + + if (opts.jar) { + // The filename was given with the -jar option. + sys.path.insert(0, pyFileName); runJar(opts.filename); - } catch (Throwable t) { - Py.printException(t); - System.exit(-1); - } - } else if (opts.filename.equals("-")) { - try { - interp.globals.__setitem__(new PyString("__file__"), new PyString("")); - interp.execfile(System.in, ""); - } catch (Throwable t) { - Py.printException(t); - } - } else { - try { - interp.globals.__setitem__(new PyString("__file__"), - new PyString(opts.filename)); - - FileInputStream file; - try { - file = new FileInputStream(new RelativeFile(opts.filename)); - } catch (FileNotFoundException e) { - throw Py.IOError(e); - } - try { - boolean isInteractive = false; - try { - isInteractive = PosixModule.getPOSIX().isatty(file.getFD()); - } catch (SecurityException ex) {} - if (isInteractive) { - opts.interactive = true; - interp.interact(null, new PyFile(file)); - return; - } else { - interp.execfile(file, opts.filename); - } - } finally { - file.close(); - } - } catch (Throwable t) { - if (t instanceof PyException - && ((PyException)t).match(_systemrestart.SystemRestart)) { - // Shutdown this instance... - shouldRestart = true; - shutdownInterpreter(); - interp.cleanup(); - // ..reset the state... - Py.setSystemState(new PySystemState()); - // ...and start again - return; - } else { - Py.printException(t); - interp.cleanup(); - System.exit(-1); + sts = Status.OK; + + } else { + /* + * The filename was given as the leading argument after the options. Our first + * approach is to treat it as an archive (or directory) in which to find a + * __main__.py (as per PEP 338). The handler for this inserts the module at + * sys.path[0] if it runs. It may raise exceptions, but only SystemExit as runpy + * deals with the others. + */ + sts = runMainFromImporter(pyFileName); + + if (sts == Status.NOT_RUN) { + /* + * The filename was not a suitable source for import, so treat it as a file + * to execute. The handler for this inserts the parent of the file at + * sys.path[0]. + */ + sts = runFile(opts.filename, interp); + // If we really had no script, do not go interactive at the end. + haveScript = sts != Status.NO_FILE; } } - } - } else { - // if there was no file name on the command line, then "" is the first element - // on sys.path. This is here because if there /was/ a filename on the c.l., - // and say the -i option was given, sys.path[0] will have gotten filled in - // with the dir of the argument filename. - Py.getSystemState().path.insert(0, Py.EmptyString); - if (opts.command != null) { - try { - interp.exec(opts.command); - } catch (Throwable t) { - Py.printException(t); - System.exit(1); + } else { // filename == null + // There is no script. (No argument or it was "-".) + if (haveDash) { + sys.argv.set(0, Py.newString('-')); } - } - - if (opts.moduleName != null) { - runModule(interp, opts.moduleName); - interp.cleanup(); - return; - } - } + sys.path.insert(0, Py.EmptyString); - if (opts.fixInteractive || (opts.filename == null && opts.command == null)) { - // Go interactive with the console: the parser needs to know the encoding. - String encoding = Py.getConsole().getEncoding(); - // Run the interpreter interactively - try { - interp.cflags.encoding = encoding; - if (!opts.interactive) { - // Don't print prompts. http://bugs.jython.org/issue2325 - interp._interact(null, null); + // Genuinely interactive, or just interpreting piped instructions? + if (stdinIsInteractive) { + // If genuinely interactive, SystemExit should mean exit the application. + Options.inspect = false; + // If genuinely interactive, run a start-up file if one is specified. + runStartupFile(interp); } - else { - interp.interact(null, null); - } - } catch (Throwable t) { - Py.printException(t); - } - } - interp.cleanup(); - } + // Run from console: exceptions other than SystemExit are handled in the REPL. + sts = runStream(System.in, "", interp); + } - /** - * Run any finalizations on the current interpreter in preparation for a SytemRestart. - */ - public static void shutdownInterpreter() { - // Stop all the active threads and signal the SystemRestart - thread.interruptAllThreads(); - Py.getSystemState()._systemRestart = true; - // Close all sockets -- not all of their operations are stopped by - // Thread.interrupt (in particular pre-nio sockets) - try { - imp.load("socket").__findattr__("_closeActiveSockets").__call__(); } catch (PyException pye) { - // continue + // Whatever the mode of execution an uncaught PyException lands here. + // If pye was SystemExit *and* Options.inspect==false, this will exit the JVM: + Py.printException(pye); + // It was an exception other than SystemExit or Options.inspect==true. + sts = Status.ERROR; } - } - /** - * Return an array of trimmed strings by splitting the argument at each occurrence of a - * separator character. (Helper for configuration variable processing.) Segments of zero length - * after trimming emerge as null. If there are more than the specified number of - * segments the last element of the array contains all of the source string after the - * (n-1)th occurrence of sep. - * - * @param spec to split - * @param sep character on which to split - * @param n number of parts to split into - * @return n-element array of strings (or nulls) - */ - private static String[] splitString(String spec, char sep, int n) { - String[] list = new String[n]; - int p = 0, i = 0, L = spec.length(); - while (p < L) { - int c = spec.indexOf(sep, p); - if (c < 0 || i >= n - 1) { - // No more seps, or no more space: i.th piece is the rest of spec. - c = L; + /* + * Check this environment variable at the end, to give programs the opportunity to set it + * from Python. + */ + if (!Options.inspect) { + // If set from Python, the value will be in os.environ, not Java System.getenv. + Options.inspect = Py.getenv("PYTHONINSPECT", "").length() > 0; + } + + if (Options.inspect && stdinIsInteractive && haveScript) { + /* + * The inspect flag is set (-i option) so we've been asked to end with an interactive + * session: the console is interactive, and we have just executed some kind of script + * (i.e. it wasn't already an interactive session). + */ + try { + // Ensure that this time SystemExit means exit. + Options.inspect = false; + // Run from console: exceptions other than SystemExit are handled in the REPL. + sts = runStream(System.in, "", interp); + } catch (PyException pye) { + // Exception from the execution of Python code. + Py.printException(pye); // SystemExit will exit the JVM here. + sts = Status.ERROR; } - String s = spec.substring(p, c).trim(); - list[i++] = (s.length() > 0) ? s : null; - p = c + 1; } - return list; + + /* + * If we arrive here then we ran some Python code. It is possible that threads we started + * are still running, so if the status is currently good, just return into the JVM. (This + * exits with good status if nothing goes wrong subsequently.) + */ + if (sts != Status.OK) { + // Something went wrong running Python code: shut down in a tidy way. + interp.cleanup(); + exit(sts); + } } /** @@ -491,210 +707,385 @@ private static boolean addDefault(Properties registry, String key, String value) } /** - * Get the value of an environment variable, if we are allowed to and it exists; otherwise - * return null. We are allowed to access the environment variable if the -E flag - * was not given and the application has permission to read environment variables. The -E flag - * is reflected in {@link Options#ignore_environment}, and will be set automatically if it turns - * out we do not have permission. + * Provides default registry entries from particular supported environment variables, obtained + * by calls to {@link #getenv(String)}. If a corresponding entry already exists in the + * properties passed, it takes precedence. * - * @param varname name to access in the environment - * @return the value or null. + * @param registry to be (possibly) updated */ - private static String getenv(String varname) { + private static void addDefaultsFromEnvironment(Properties registry) { + + // Pick up the path from the environment + addDefault(registry, "python.path", getenv("JYTHONPATH")); + + // Runs at the start of each (wholly) interactive session. + addDefault(registry, "python.startup", getenv("JYTHONSTARTUP")); + // Go interactive after script. (PYTHONINSPECT because Python scripts may set it.) + addDefault(registry, "python.inspect", getenv("PYTHONINSPECT")); + + // Read environment variable PYTHONIOENCODING into properties (registry) + String pythonIoEncoding = getenv("PYTHONIOENCODING"); + if (pythonIoEncoding != null) { + String[] spec = pythonIoEncoding.split(":", 2); + // Note that if encoding or errors is blank (=null), the registry value wins. + addDefault(registry, RegistryKey.PYTHON_IO_ENCODING, spec[0]); + if (spec.length > 1) { + addDefault(registry, RegistryKey.PYTHON_IO_ERRORS, spec[1]); + } + } + } + + /** The same as {@code getenv(name, null)}. */ + private static String getenv(String name) { + return getenv(name, null); + } + + /** + * Get the value of an environment variable, respecting {@link Options#ignore_environment} (the + * -E option), or return the given default if the variable is undefined or the security + * environment prevents access. An empty string value from the environment is treated as + * undefined. + *

    + * This accesses the read-only Java copy of the system environment directly, not + * {@code os.environ} so that it is safe to use before Python types are available. + * + * @param name to access in the environment (if allowed by + * {@link Options#ignore_environment}=={@code false}). + * @param defaultValue to return if {@code name} is not defined or "" or access is forbidden. + * @return the corresponding value or defaultValue. + */ + private static String getenv(String name, String defaultValue) { if (!Options.ignore_environment) { try { - return System.getenv(varname); + String value = System.getenv(name); + return (value != null && value.length() > 0) ? value : defaultValue; } catch (SecurityException e) { // We're not allowed to access them after all Options.ignore_environment = true; } } - return null; + return defaultValue; } -} + /** Non-fatal error message when ignoring unsupported option (usually one valid for CPython). */ + private static void optionNotSupported(char option) { + printError("Option -%c is not supported", option); + } -class CommandLineOptions { - - public String filename; - public boolean jar, interactive, notice; - public boolean runCommand, runModule; - public boolean fixInteractive; - public boolean help, version; - public String[] argv; - public Properties properties; - public String command; - public List warnoptions = Generic.list(); - public String encoding; - public String division; - public String moduleName; - - public CommandLineOptions() { - filename = null; - jar = fixInteractive = false; - interactive = notice = true; - runModule = false; - properties = new Properties(); - help = version = false; + /** + * Print {@code "jython: "} on {@code System.err} as one line. + * + * @param format suitable to use in {@code String.format(format, args)} + * @param args zero or more args + */ + private static void printError(String format, Object... args) { + System.err.println(String.format("jython: " + format, args)); } - public void setProperty(String key, String value) { - properties.put(key, value); - try { - System.setProperty(key, value); - } catch (SecurityException e) { - // continue + /** + * Append strings to a PyList as {@code bytes/str} objects. These might come from the command + * line, or any source with the possibility of non-ascii values. + * + * @param source of {@code String}s + * @param destination list + */ + private static void addFSEncoded(Iterable source, PyList destination) { + for (String s : source) { + destination.add(Py.fileSystemEncode(s)); } } - private boolean argumentExpected(String arg) { - System.err.println("Argument expected for the " + arg + " option"); - return false; - } + /** + * Class providing a parser for Jython command line options. Many of the allowable options set + * values directly in the static {@link Options} as the parser runs, while others set values in + * (an instance) of this class. + */ + static class CommandLineOptions { - public boolean parse(String[] args) { - int index = 0; - - while (index < args.length && args[index].startsWith("-")) { - String arg = args[index]; - if (arg.equals("-h") || arg.equals("-?") || arg.equals("--help")) { - help = true; - return false; - } else if (arg.equals("-V") || arg.equals("--version")) { - version = true; - return false; - } else if (arg.equals("-")) { - if (!fixInteractive) { - interactive = false; - } - filename = "-"; - } else if (arg.equals("-i")) { - fixInteractive = true; - interactive = true; - } else if (arg.equals("-jar")) { - jar = true; - if (!fixInteractive) { - interactive = false; - } - } else if (arg.equals("-u")) { - Options.unbuffered = true; - } else if (arg.equals("-v")) { - Options.verbose++; - } else if (arg.equals("-vv")) { - Options.verbose += 2; - } else if (arg.equals("-vvv")) { - Options.verbose += 3; - } else if (arg.equals("-s")) { - Options.no_user_site = true; - } else if (arg.equals("-S")) { - Options.importSite = false; - } else if (arg.equals("-B")) { - Options.dont_write_bytecode = true; - } else if (arg.startsWith("-c")) { - runCommand = true; - if (arg.length() > 2) { - command = arg.substring(2); - } else if ((index + 1) < args.length) { - command = args[++index]; - } else { - return argumentExpected(arg); - } - if (!fixInteractive) { - interactive = false; - } - index++; - break; - } else if (arg.startsWith("-W")) { - if (arg.length() > 2) { - warnoptions.add(arg.substring(2)); - } else if ((index + 1) < args.length) { - warnoptions.add(args[++index]); - } else { - return argumentExpected(arg); - } - } else if (arg.equals("-E")) { - // -E (ignore environment variables) - Options.ignore_environment = true; - } else if (arg.startsWith("-D")) { - String key = null; - String value = null; - int equals = arg.indexOf("="); - if (equals == -1) { - String arg2 = args[++index]; - key = arg.substring(2, arg.length()); - value = arg2; - } else { - key = arg.substring(2, equals); - value = arg.substring(equals + 1, arg.length()); - } - setProperty(key, value); - } else if (arg.startsWith("-Q")) { - if (arg.length() > 2) { - division = arg.substring(2); - } else { - division = args[++index]; - } - } else if (arg.startsWith("-m")) { - runModule = true; - if (arg.length() > 2) { - moduleName = arg.substring(2); - } else if ((index + 1) < args.length) { - moduleName = args[++index]; - } else { - return argumentExpected(arg); - } - if (!fixInteractive) { - interactive = false; - } + /** Possible actions to take after processing the options. */ + enum Action { + RUN, ERROR, HELP, VERSION + }; - index++; - int n = args.length - index + 1; - argv = new String[n]; - argv[0] = moduleName; - for (int i = 1; index < args.length; i++, index++) { - argv[i] = args[index]; - } - return true; - } else if (arg.startsWith("-3")) { - Options.py3k_warning = true; - } else { - String opt = args[index]; - if (opt.startsWith("--")) { - opt = opt.substring(2); - } else if (opt.startsWith("-")) { - opt = opt.substring(1); + /** The action to take after processing the options. */ + Action action = Action.RUN; + /** Set informatively when {@link #action}{@code ==ERROR}. */ + String message = ""; + + /** Argument to the -c option. */ + String command; + /** First argument that is not an option (therefore the executable file). */ + String filename; + /** Argument to the -m option. */ + String module; + + /** -h or --help option. */ + boolean help = false; + /** -V or --version option. */ + boolean version = false; + /** -jar option. */ + boolean jar = false; + /** Count of -v options. */ + int verbosity = 0; + + /** Collects definitions made with the -D option directly to Jython (not java -D). */ + Properties properties = new Properties(); + + /** Arguments after the first non-option, therefore arguments to the executable program. */ + List argv = new LinkedList(); + /** Arguments collected from succesive -W options. */ + List warnoptions = new LinkedList(); + + /** Valid single character options. ':' means expect an argument following. */ + // XJD are extra to CPython. X and J are sanctioned while D may one day clash. + static final String PROGRAM_OPTS = "3bBc:dEhim:OQ:RsStuUvVW:x?" + "XJD:"; + + /** Valid long-name options. */ + static final char JAR_OPTION = '\u2615'; + static final OptionScanner.LongSpec[] PROGRAM_LONG_OPTS = + {new OptionScanner.LongSpec("--", OptionScanner.DONE), + new OptionScanner.LongSpec("--help", 'h'), + new OptionScanner.LongSpec("--version", 'V'), + new OptionScanner.LongSpec("-jar", JAR_OPTION, true), // Yes, just one dash. + }; + + /** + * Parse the arguments into the static {@link Options} and a returned instance of this + * class. + * + * @param args from program invocation. + * @return + */ + static CommandLineOptions parse(String args[]) { + CommandLineOptions opts = new CommandLineOptions(); + opts._parse(args); + return opts; + } + + /** Parser implementation. Do not call this twice on the same instance. */ + private void _parse(String args[]) { + // Create a scanner with the right tables for Python/Jython + OptionScanner scanner = new OptionScanner(args, PROGRAM_OPTS, PROGRAM_LONG_OPTS); + _parse(scanner, args); + if (action == Action.RUN) { + // Squirrel away the unprocessed arguments + while (scanner.countRemainingArguments() > 0) { + argv.add(scanner.getWholeArgument()); } - System.err.println("Unknown option: " + opt); - return false; } - index += 1; } - notice = interactive; - if (filename == null && index < args.length && command == null) { - filename = args[index++]; - if (!fixInteractive) { - interactive = false; + + /** + * Parse options into object state, until we encounter the first argument. This is a helper + * to {@link #_parse(String[])}. + */ + private void _parse(OptionScanner scanner, String args[]) { + char c; + /* + * The default action is RUN, taken when we all the options have been processed, and + * either we have run out of arguments (we'll start an interactive session) or + * encountered a non-option argument, which ought to name the file to execute. + * Executable options (like -m and -c) cause a return with action==RUN from their case. + * Any errors, and some special options like --help and -V, return set some other action + * than RUN, ending the loop. + */ + while (action == Action.RUN && (c = scanner.getOption()) != OptionScanner.DONE) { + + switch (c) { + /* + * The first 4 cases all terminate the options in with a RUN action, meaning + * that this option defines the executable script and the arguments following + * will be passed to the script. + */ + case 'c': + /* + * -c is the last option; following arguments that look like options are + * left for the command to interpret. + */ + command = scanner.getOptionArgument() + "\n"; + return; + + case 'm': + /* + * -m is the last option; following arguments that look like options are + * left for the module to interpret. + */ + module = scanner.getOptionArgument(); + return; + + case JAR_OPTION: + /* + * -jar is the last option; following arguments that look like options are + * left for __run__.py to interpret. + */ + jar = true; + filename = scanner.getOptionArgument(); + return; + + case OptionScanner.ARGUMENT: + /* + * This should be a file name (or "-", meaning stdin); following arguments + * that look like options are left for the code it contains to interpret. + */ + filename = scanner.getWholeArgument(); + return; + + // Options that don't terminate option processing (mostly). + + case 'b': + case 'd': + optionNotSupported(c); + break; + + case '3': + Options.py3k_warning = true; + if (Options.division_warning == 0) { + Options.division_warning = 1; + } + break; + + case 'Q': + switch (scanner.getOptionArgument()) { + case "old": + Options.division_warning = 0; + break; + case "warn": + Options.division_warning = 1; + break; + case "warnall": + Options.division_warning = 2; + break; + case "new": + Options.Qnew = true; + default: + error("-Q option should be `-Qold', " + + "`-Qwarn', `-Qwarnall', or `-Qnew' only"); + } + break; + + case 'i': + Options.inspect = Options.interactive = true; + break; + + case 'O': + Options.optimize++; + break; + + case 'B': + Options.dont_write_bytecode = true; + break; + + case 's': + Options.no_user_site = true; + break; + + case 'S': + Options.no_site = true; + Options.importSite = false; + break; + + case 'E': + Options.ignore_environment = true; + break; + + case 't': + optionNotSupported(c); + // Py_TabcheckFlag++; + break; + + case 'u': + Options.unbuffered = true; + break; + + case 'v': + verbosity++; + break; + + case 'x': + optionNotSupported(c); + // skipfirstline = true; + break; + + // case 'X': reserved for implementation-specific arguments + + case 'U': + optionNotSupported(c); + // Py_UnicodeFlag++; + break; + + case 'W': + warnoptions.add(scanner.getOptionArgument()); + break; + + case 'R': + optionNotSupported(c); + break; + + case 'D': + // Definitions made on the command line: -Dprop=v + try { + optionD(scanner); + } catch (SecurityException e) { + // Prevented by security policy. + } + break; + + // Options that terminate option processing with something other than RUN. + + case 'h': + case '?': + action = Action.HELP; + break; + + case 'V': + action = Action.VERSION; + break; + + case 'J': + /* + * This shouldn't happen because the launcher should have recognised this + * and converted it to an option or argument to the java command. If it + * shows up here, maybe it was supplied outside the loader or the context + * has confused the launcher. + */ + error("-J is only valid when using the Jython launcher. " + + "In a complex command, put the -J options early."); + break; + + case OptionScanner.ERROR: + error(scanner.getMessage()); + break; + + default: + // Acceptable to the scanner, but missing from the case statement? + error("parser did not recognise option -%c \\u%04x", c, c); + break; + } } - notice = false; - } - if (command != null) { - notice = false; } - int n = args.length - index + 1; - argv = new String[n]; - if (filename != null) { - argv[0] = filename; - } else if (command != null) { - argv[0] = "-c"; - } else { - argv[0] = ""; + /** + * Helper for option {@code -Dprop=v}, adding to the "post-properties". (This is a + * clash-in-waiting with Python.) The effect is slightly different from {@code -J-Dprop=v}, + * which contributes to the "pre-properties". + */ + private void optionD(OptionScanner scanner) throws SecurityException { + String[] kv = scanner.getOptionArgument().split("=", 2); + String prop = kv[0].trim(); + if (kv.length > 1) { + properties.put(prop, kv[1]); + } else { + properties.put(prop, ""); + } } - for (int i = 1; i < n; i++, index++) { - argv[i] = args[index]; + /** + * Set the error message as {@code String.format(message, args)} and set the action to + * {@link Action#ERROR}. + */ + private void error(String message, Object... args) { + this.message = args.length == 0 ? message : String.format(message, args); + action = Action.ERROR; } - - return true; } } diff --git a/src/shell/jython b/src/shell/jython index 5a4567b00..a0596692c 100755 --- a/src/shell/jython +++ b/src/shell/jython @@ -109,10 +109,8 @@ if [ -z "$JAVA_MEM" ] ; then fi if [ -z "$JAVA_STACK" ]; then - # 32 bit Java 6 needs the stack increased to at least 512k for - # test_cpickle to pass, but we don't want to shrink 64 bit Java's - # default of 1024k - JAVA_STACK=-Xss1024k + # test_marshal.py needs a Xss of 2560k to pass + JAVA_STACK=-Xss2560k fi JAVA_ENCODING="" diff --git a/src/shell/jython.exe b/src/shell/jython.exe index 2a03827dd..56a68742d 100755 Binary files a/src/shell/jython.exe and b/src/shell/jython.exe differ diff --git a/src/shell/jython.py b/src/shell/jython.py index bf70b7f91..952a93a2f 100644 --- a/src/shell/jython.py +++ b/src/shell/jython.py @@ -1,17 +1,20 @@ -#!/usr/bin/env python2.7 -E +#!/usr/bin/env python2.7 # -*- coding: utf-8 -*- -# Launch script for Jython. It may be wrapped as an executable with -# tools like PyInstaller, creating jython.exe, or run directly. The -# installer will make this the default launcher under the name -# bin/jython if CPython 2.7 is available with the above shebang -# invocation. +# Launch script for Jython. It may be run directly (note the shebang line), but +# importantly it supplies python.exe, the launcher we use on Windows. +# +# Each time this file changes, we must regenerate an executable with +# PyInstaller, using the command: +# +# pyinstaller --onefile jython.py +# +# This is best done in a virtual environment (more about this in the Jython +# Developers' Guide). import glob -import inspect import os import os.path -import pipes import shlex import subprocess import sys @@ -20,19 +23,86 @@ is_windows = os.name == "nt" or (os.name == "java" and os._name == "nt") +# A note about encoding: +# +# A major motivation for this program is to launch Jython on Windows, where +# console and file encoding may be different. Command-line arguments and +# environment variables are presented in Python 2.7 as byte-data, encoded +# "somehow". It becomes important to know which decoding to use as soon as +# paths may contain non-ascii characters. It is not the console encoding. +# Experiment shows that sys.getfilesystemencoding() is generally applicable +# to arguments, environment variables and spawning a subprocess. +# +# On a Windows 10 box, this comes up with pseudo-codec 'mbcs'. This supports +# European accented characters pretty well. +# +# When localised to Chinese(simplified) the FS encoding mbcs includes many +# more points than cp936 (the console encoding), although it still struggles +# with European accented characters. + +ENCODING = sys.getfilesystemencoding() or "utf-8" + + +def get_env(envvar, default=None): + """ Return the named environment variable, decoded to Unicode.""" + v = os.environ.get(envvar, default) + # Result may be bytes but we want unicode for the command + if isinstance(v, bytes): + v = v.decode(ENCODING) + # Remove quotes sometimes necessary around the value + if v is not None and v.startswith('"') and v.endswith('"'): + v = v[1:-1] + return v + +def get_env_mem(envvar, default): + """ Return the named memory environment variable, decoded to Unicode. + The default should begin with -Xmx or -Xss as in the java command, + but this part will be added to the environmental value if missing. + """ + # Tolerate default given as bytes, as we're bound to forget sometimes + if isinstance(default, bytes): + default = default.decode(ENCODING) + v = os.environ.get(envvar, default) + # Result may be bytes but we want unicode for the command + if isinstance(v, bytes): + v = v.decode(ENCODING) + # Accept either a form like 16m or one like -Xmx16m + if not v.startswith(u"-X"): + v = default[:4] + v + return v + +def encode_list(args, encoding=ENCODING): + """ Convert list of Unicode strings to list of encoded byte strings.""" + r = [] + for a in args: + if not isinstance(a, bytes): a = a.encode(encoding) + r.append(a) + return r + +def decode_list(args, encoding=ENCODING): + """ Convert list of byte strings to list of Unicode strings.""" + r = [] + for a in args: + if not isinstance(a, unicode): a = a.decode(encoding) + r.append(a) + return r def parse_launcher_args(args): + """ Process the given argument list into two objects, the first part being + a namespace of checked arguments to the interpreter itself, and the rest + being the Python program it will run and its arguments. + """ class Namespace(object): pass parsed = Namespace() - parsed.java = [] - parsed.properties = OrderedDict() - parsed.boot = False - parsed.jdb = False - parsed.help = False - parsed.print_requested = False - parsed.profile = False - parsed.jdb = None + parsed.boot = False # --boot flag given + parsed.jdb = False # --jdb flag given + parsed.help = False # --help or -h flag given + parsed.print_requested = False # --print flag given + parsed.profile = False # --profile flag given + parsed.properties = OrderedDict() # properties to give the JVM + parsed.java = [] # any other arguments to give the JVM + unparsed = list() it = iter(args) next(it) # ignore sys.argv[0] @@ -42,11 +112,11 @@ class Namespace(object): arg = next(it) except StopIteration: break - if arg.startswith("-D"): - k, v = arg[2:].split("=") + if arg.startswith(u"-D"): + k, v = arg[2:].split(u"=") parsed.properties[k] = v i += 1 - elif arg in ("-J-classpath", "-J-cp"): + elif arg in (u"-J-classpath", u"-J-cp"): try: next_arg = next(it) except StopIteration: @@ -55,30 +125,34 @@ class Namespace(object): bad_option("Bad option for -J-classpath") parsed.classpath = next_arg i += 2 - elif arg.startswith("-J-Xmx"): + elif arg.startswith(u"-J-Xmx"): parsed.mem = arg[2:] i += 1 - elif arg.startswith("-J-Xss"): + elif arg.startswith(u"-J-Xss"): parsed.stack = arg[2:] i += 1 - elif arg.startswith("-J"): + elif arg.startswith(u"-J"): parsed.java.append(arg[2:]) i += 1 - elif arg == "--print": + elif arg == u"--print": parsed.print_requested = True i += 1 - elif arg in ("-h", "--help"): + elif arg in (u"-h", u"--help"): parsed.help = True - elif arg in ("--boot", "--jdb", "--profile"): + elif arg in (u"--boot", u"--jdb", u"--profile"): setattr(parsed, arg[2:], True) i += 1 - elif arg == "--": + elif len(arg) >= 2 and arg[0] == u'-' and arg[1] in u"BEisSuvV3": + unparsed.append(arg) + i += 1 + elif arg == u"--": i += 1 break else: break - return parsed, args[i:] + unparsed.extend(args[i:]) + return parsed, unparsed class JythonCommand(object): @@ -92,13 +166,13 @@ def uname(self): if hasattr(self, "_uname"): return self._uname if is_windows: - self._uname = "windows" + self._uname = u"windows" else: uname = subprocess.check_output(["uname"]).strip().lower() if uname.startswith("cygwin"): - self._uname = "cygwin" + self._uname = u"cygwin" else: - self._uname = uname + self._uname = uname.decode(ENCODING) return self._uname @property @@ -114,22 +188,23 @@ def java_command(self): return self._java_command def setup_java_command(self): + """ Sets java_home and java_command according to environment and parsed + launcher arguments --jdb and --help. + """ if self.args.help: self._java_home = None - self._java_command = "java" + self._java_command = u"java" return - - if "JAVA_HOME" not in os.environ: - self._java_home = None - self._java_command = "jdb" if self.args.jdb else "java" + + command = u"jdb" if self.args.jdb else u"java" + + self._java_home = get_env("JAVA_HOME") + if self._java_home is None or self.uname == u"cygwin": + # Assume java or jdb on the path + self._java_command = command else: - self._java_home = os.environ["JAVA_HOME"] - if self.uname == "cygwin": - self._java_command = "jdb" if self.args.jdb else "java" - else: - self._java_command = os.path.join( - self.java_home, "bin", - "jdb" if self.args.jdb else "java") + # Assume java or jdb in JAVA_HOME/bin + self._java_command = os.path.join(self._java_home, u"bin", command) @property def executable(self): @@ -139,28 +214,42 @@ def executable(self): # Modified from # http://stackoverflow.com/questions/3718657/how-to-properly-determine-current-script-directory-in-python/22881871#22881871 if getattr(sys, "frozen", False): # py2exe, PyInstaller, cx_Freeze - path = os.path.abspath(sys.executable) + # Frozen. Let it go with the executable path. + bytes_path = sys.executable else: - def inspect_this(): pass - path = inspect.getabsfile(inspect_this) - self._executable = os.path.realpath(path) + # Not frozen. Use the __file__ of this module. + bytes_path = __file__ + # Python 2 thinks in bytes. Carefully normalise in Unicode. + path = os.path.realpath(bytes_path.decode(ENCODING)) + try: + # If shorter, make this relative to the CWD. + relpath = os.path.relpath(path, os.getcwdu()) + if len(relpath) < len(path): path = relpath + except ValueError: + # Many reasons why this might be impossible: use an absolute path. + path = os.path.abspath(path) + self._executable = path return self._executable @property def jython_home(self): if hasattr(self, "_jython_home"): return self._jython_home - if "JYTHON_HOME" in os.environ: - self._jython_home = os.environ["JYTHON_HOME"] - else: - self._jython_home = os.path.dirname(os.path.dirname(self.executable)) - if self.uname == "cygwin": - self._jython_home = subprocess.check_output(["cygpath", "--windows", self._jython_home]).strip() + home = get_env("JYTHON_HOME") + if home is None: + # Not just dirname twice in case dirname(executable) == '' + home = os.path.join(os.path.dirname(self.executable), u'..') + # This could be a relative path like .\.. + home = os.path.normpath(home) + if self.uname == u"cygwin": + # Even on Cygwin, we need a Windows-style path for this + home = unicode_subprocess(["cygpath", "--windows", home]) + self._jython_home = home return self._jython_home @property def jython_opts(): - return os.environ.get("JYTHON_OPTS", "") + return get_env("JYTHON_OPTS", "") @property def classpath_delimiter(self): @@ -179,11 +268,9 @@ def jython_jars(self): else: jars.append(os.path.join(self.jython_home, "javalib", "*")) elif not os.path.exists(os.path.join(self.jython_home, "jython.jar")): - bad_option("""{jython_home} contains neither jython-dev.jar nor jython.jar. + bad_option(u"""{} contains neither jython-dev.jar nor jython.jar. Try running this script from the 'bin' directory of an installed Jython or -setting {envvar_specifier}JYTHON_HOME.""".format( - jython_home=self.jython_home, - envvar_specifier="%" if self.uname == "windows" else "$")) +setting JYTHON_HOME.""".format(self.jython_home)) else: jars = [os.path.join(self.jython_home, "jython.jar")] self._jython_jars = jars @@ -194,26 +281,26 @@ def java_classpath(self): if hasattr(self.args, "classpath"): return self.args.classpath else: - return os.environ.get("CLASSPATH", ".") + return get_env("CLASSPATH", ".") @property def java_mem(self): if hasattr(self.args, "mem"): return self.args.mem else: - return os.environ.get("JAVA_MEM", "-Xmx512m") + return get_env_mem("JAVA_MEM", "-Xmx512m") @property def java_stack(self): if hasattr(self.args, "stack"): return self.args.stack else: - return os.environ.get("JAVA_STACK", "-Xss1024k") + return get_env_mem("JAVA_STACK", "-Xss2560k") @property def java_opts(self): return [self.java_mem, self.java_stack] - + @property def java_profile_agent(self): return os.path.join(self.jython_home, "javalib", "profile.jar") @@ -222,68 +309,84 @@ def set_encoding(self): if "JAVA_ENCODING" not in os.environ and self.uname == "darwin" and "file.encoding" not in self.args.properties: self.args.properties["file.encoding"] = "UTF-8" - def convert(self, arg): - if sys.stdout.encoding: - return arg.encode(sys.stdout.encoding) - else: - return arg - def make_classpath(self, jars): return self.classpath_delimiter.join(jars) def convert_path(self, arg): - if self.uname == "cygwin": - if not arg.startswith("/cygdrive/"): - new_path = self.convert(arg).replace("/", "\\") + if self.uname == u"cygwin": + if not arg.startswith(u"/cygdrive/"): + return arg.replace(u"/", u"\\") else: - new_path = subprocess.check_output(["cygpath", "-pw", self.convert(arg)]).strip() - return new_path + arg = arg.replace('*', r'\*') # prevent globbing + return unicode_subprocess(["cygpath", "-pw", arg]) else: - return self.convert(arg) + return arg + + def unicode_subprocess(self, unicode_command): + """ Launch a command with subprocess.check_output() and read the + output, except everything is expected to be in Unicode. + """ + cmd = [] + for c in unicode_command: + if isinstance(c, bytes): + cmd.append(c) + else: + cmd.append(c.encode(ENCODING)) + return subprocess.check_output(cmd).strip().decode(ENCODING) @property def command(self): + # Set default file encoding for just for Darwin (?) self.set_encoding() + + # Begin to build the Java part of the ultimate command args = [self.java_command] args.extend(self.java_opts) args.extend(self.args.java) + # Get the class path right (depends on --boot) classpath = self.java_classpath jython_jars = self.jython_jars if self.args.boot: - args.append("-Xbootclasspath/a:%s" % self.convert_path(self.make_classpath(jython_jars))) + args.append(u"-Xbootclasspath/a:%s" % self.convert_path(self.make_classpath(jython_jars))) else: classpath = self.make_classpath(jython_jars) + self.classpath_delimiter + classpath - args.extend(["-classpath", self.convert_path(classpath)]) + args.extend([u"-classpath", self.convert_path(classpath)]) if "python.home" not in self.args.properties: - args.append("-Dpython.home=%s" % self.convert_path(self.jython_home)) + args.append(u"-Dpython.home=%s" % self.convert_path(self.jython_home)) if "python.executable" not in self.args.properties: - args.append("-Dpython.executable=%s" % self.convert_path(self.executable)) + args.append(u"-Dpython.executable=%s" % self.convert_path(self.executable)) if "python.launcher.uname" not in self.args.properties: - args.append("-Dpython.launcher.uname=%s" % self.uname) - # Determines whether running on a tty for the benefit of + args.append(u"-Dpython.launcher.uname=%s" % self.uname) + + # Determine whether running on a tty for the benefit of # running on Cygwin. This step is needed because the Mintty # terminal emulator doesn't behave like a standard Microsoft # Windows tty, and so JNR Posix doesn't detect it properly. if "python.launcher.tty" not in self.args.properties: - args.append("-Dpython.launcher.tty=%s" % str(os.isatty(sys.stdin.fileno())).lower()) - if self.uname == "cygwin" and "python.console" not in self.args.properties: - args.append("-Dpython.console=org.python.core.PlainConsole") + args.append(u"-Dpython.launcher.tty=%s" % str(os.isatty(sys.stdin.fileno())).lower()) + if self.uname == u"cygwin" and "python.console" not in self.args.properties: + args.append(u"-Dpython.console=org.python.core.PlainConsole") + if self.args.profile: - args.append("-XX:-UseSplitVerifier") - args.append("-javaagent:%s" % self.convert_path(self.java_profile_agent)) + args.append(u"-XX:-UseSplitVerifier") + args.append(u"-javaagent:%s" % self.convert_path(self.java_profile_agent)) + for k, v in self.args.properties.iteritems(): - args.append("-D%s=%s" % (self.convert(k), self.convert(v))) - args.append("org.python.util.jython") + args.append(u"-D%s=%s" % (k, v)) + + args.append(u"org.python.util.jython") + if self.args.help: - args.append("--help") + args.append(u"--help") + args.extend(self.jython_args) return args def bad_option(msg): - print >> sys.stderr, """ + print >> sys.stderr, u""" {msg} usage: jython [option] ... [-c cmd | -m mod | file | -] [arg] ... Try `jython -h' for more information. @@ -303,28 +406,33 @@ def print_help(): --profile: run with the Java Interactive Profiler (http://jiprof.sf.net) -- : pass remaining arguments through to Jython Jython launcher environment variables: -JAVA_MEM : Java memory (sets via -Xmx) +JAVA_MEM : Java memory size as a java option e.g. -Xmx600m or just 600m +JAVA_STACK : Java stack size as a java option e.g. -Xss5120k or just 5120k JAVA_OPTS : options to pass directly to Java -JAVA_STACK : Java stack size (sets via -Xss) JAVA_HOME : Java installation directory JYTHON_HOME: Jython installation directory JYTHON_OPTS: default command line arguments """ def support_java_opts(args): + """ Generator from options intended for the JVM. Options beginning -D go + through unchanged, others are prefixed with -J. + """ + # Input is expected to be Unicode, but just in case ... + if isinstance(args, bytes): args = args.decode(ENCODING) it = iter(args) while it: arg = next(it) - if arg.startswith("-D"): + if arg.startswith(u"-D"): yield arg - elif arg in ("-classpath", "-cp"): - yield "-J" + arg + elif arg in (u"-classpath", u"-cp"): + yield u"-J" + arg try: yield next(it) except StopIteration: bad_option("Argument expected for -classpath option in JAVA_OPTS") else: - yield "-J" + arg + yield u"-J" + arg # copied from subprocess module in Jython; see @@ -378,37 +486,63 @@ def cmdline2list(cmdline): return argv +def get_env_opts(envvar): + """ Return a list of the values in the named environment variable, + split according to shell conventions, and decoded to Unicode. + """ + opts = os.environ.get(envvar, "") # bytes at this point + if is_windows: + opts = cmdline2list(opts) + else: + opts = shlex.split(opts) + return decode_list(opts) -def decode_args(sys_args): - args = [sys_args[0]] - - def get_env_opts(envvar): - opts = os.environ.get(envvar, "") - if is_windows: - return cmdline2list(opts) - else: - return shlex.split(opts) - - java_opts = get_env_opts("JAVA_OPTS") - jython_opts = get_env_opts("JYTHON_OPTS") - - args.extend(support_java_opts(java_opts)) - args.extend(sys_args[1:]) - - if sys.stdout.encoding: - if sys.stdout.encoding.lower() == "cp65001": - sys.exit("""Jython does not support code page 65001 (CP_UTF8). -Please try another code page by setting it with the chcp command.""") - args = [arg.decode(sys.stdout.encoding) for arg in args] - jython_opts = [arg.decode(sys.stdout.encoding) for arg in jython_opts] +def maybe_quote(s): + """ Enclose the string argument in single quotes if it looks like it needs it. + Spaces and quotes will trigger; single quotes in the argument are escaped. + This is only used to compose the --print output so need only satisfy shlex. + """ + NEED_QUOTE = u" \t\"\\'" + clean = True + for c in s: + if c in NEED_QUOTE: + clean = False + break + if clean: return s + # Something needs quoting or escaping. + QUOTE = u"'" + ESC = u"\\" + arg = [QUOTE] + for c in s: + if c == QUOTE: + arg.append(QUOTE) + arg.append(ESC) + arg.append(QUOTE) + elif c == ESC: + arg.append(ESC) + arg.append(c) + arg.append(QUOTE) + return ''.join(arg) - return args, jython_opts +def main(sys_args): + # The entire program must work in Unicode + sys_args = decode_list(sys_args) + # sys_args[0] is this script (which we'll replace with 'java' eventually). + # Insert options for the java command from the environment. + sys_args[1:1] = support_java_opts(get_env_opts("JAVA_OPTS")) -def main(sys_args): - sys_args, jython_opts = decode_args(sys_args) + # Parse the composite arguments (yes, even the ones from JAVA_OPTS), + # and return the "unparsed" tail considered arguments for Jython itself. args, jython_args = parse_launcher_args(sys_args) + + # Build the data from which we can generate the command ultimately. + # Jython options supplied from the environment stand in front of the + # unparsed tail from the command line. + jython_opts = get_env_opts("JYTHON_OPTS") jython_command = JythonCommand(args, jython_opts + jython_args) + + # This is the "fully adjusted" command to launch, but still as Unicode. command = jython_command.command if args.profile and not args.help: @@ -416,28 +550,51 @@ def main(sys_args): os.unlink("profile.txt") except OSError: pass + if args.print_requested and not args.help: - if jython_command.uname == "windows": - print subprocess.list2cmdline(jython_command.command) + if jython_command.uname == u"windows": + # Add escapes and quotes necessary to Windows. + # Normally used for a byte strings but Python is tolerant :) + command_line = subprocess.list2cmdline(command) else: - print " ".join(pipes.quote(arg) for arg in jython_command.command) + # Transform any element that seems to need quotes + command = map(maybe_quote, command) + # Now concatenate with spaces + command_line = u" ".join(command) + # It is possible the Unicode cannot be encoded for the console + enc = sys.stdout.encoding or 'ascii' + sys.stdout.write(command_line.encode(enc, 'replace') + "\n") else: - if not (is_windows or not hasattr(os, "execvp") or args.help or jython_command.uname == "cygwin"): - # Replace this process with the java process. - # - # NB such replacements actually do not work under Windows, - # but if tried, they also fail very badly by hanging. - # So don't even try! - os.execvp(command[0], command[1:]) - else: - result = 1 - try: - result = subprocess.call(command) - if args.help: - print_help() - except KeyboardInterrupt: - pass - sys.exit(result) + try: + if not (is_windows or not hasattr(os, "execvp") or args.help or + jython_command.uname == u"cygwin"): + # Replace this process with the java process. + # + # NB such replacements actually do not work under Windows, + # but if tried, they also fail very badly by hanging. + # So don't even try! + command = encode_list(command) + os.execvp(command[0], command[1:]) + else: + result = 1 + try: + result = subprocess.call(encode_list(command)) + if args.help: + print_help() + except KeyboardInterrupt: + pass + sys.exit(result) + except OSError as e: + print >> sys.stderr, "Failed to launch Jython using command:",\ + command[0], "...\n", \ + " Use the --print option to see the command in full." + if jython_command.java_home: + print >> sys.stderr, " Launcher used JAVA_HOME =",\ + jython_command.java_home + else: + print >> sys.stderr, " Check PATH for java/jdb command." + print >> sys.stderr, e + sys.exit(1) if __name__ == "__main__": diff --git a/src/shell/python27.dll b/src/shell/python27.dll deleted file mode 100755 index 8d99ae247..000000000 Binary files a/src/shell/python27.dll and /dev/null differ diff --git a/src/templates/_json.Encoder.derived b/src/templates/_json.Encoder.derived new file mode 100644 index 000000000..83c124392 --- /dev/null +++ b/src/templates/_json.Encoder.derived @@ -0,0 +1,4 @@ +base_class: Encoder +want_dict: true +ctr: PyObject[] args, String[] kwds +incl: object diff --git a/src/templates/_json.Scanner.derived b/src/templates/_json.Scanner.derived new file mode 100644 index 000000000..616bd2211 --- /dev/null +++ b/src/templates/_json.Scanner.derived @@ -0,0 +1,4 @@ +base_class: Scanner +want_dict: true +ctr: PyObject context +incl: object diff --git a/src/templates/antlr.AST.derived b/src/templates/antlr.AST.derived new file mode 100644 index 000000000..9dd64c530 --- /dev/null +++ b/src/templates/antlr.AST.derived @@ -0,0 +1,4 @@ +base_class: AST +want_dict: true +ctr +incl: object diff --git a/src/templates/ast_Set.derived b/src/templates/ast_Set.derived new file mode 100644 index 000000000..f434acf09 --- /dev/null +++ b/src/templates/ast_Set.derived @@ -0,0 +1,4 @@ +base_class: Set +want_dict: true +ctr +incl: object diff --git a/src/templates/ast_SetComp.derived b/src/templates/ast_SetComp.derived new file mode 100644 index 000000000..ebe67dc49 --- /dev/null +++ b/src/templates/ast_SetComp.derived @@ -0,0 +1,4 @@ +base_class: SetComp +want_dict: true +ctr +incl: object diff --git a/src/templates/gderived-defs b/src/templates/gderived-defs index 2ada4b814..be232c1e0 100644 --- a/src/templates/gderived-defs +++ b/src/templates/gderived-defs @@ -109,7 +109,7 @@ define: (ClassBodyDeclarations)userdict } public void setDict(PyObject newDict) { - if (newDict instanceof PyStringMap || newDict instanceof PyDictionary ) { + if (newDict instanceof AbstractDict) { dict = newDict; if (dict.__finditem__(PyString.fromInterned("__del__")) != null && !JyAttribute.hasAttr(this, JyAttribute.FINALIZE_TRIGGER_ATTR)) { @@ -123,7 +123,7 @@ define: (ClassBodyDeclarations)userdict public void delDict() { // deleting an object's instance dict makes it grow a new one - dict = new PyStringMap(); + dict = new PyStringMap(); } define: (ClassBodyDeclarations)ctr diff --git a/src/templates/imap.derived b/src/templates/imap.derived new file mode 100644 index 000000000..10fbd7951 --- /dev/null +++ b/src/templates/imap.derived @@ -0,0 +1,4 @@ +base_class: imap +want_dict: true +ctr: +incl: object diff --git a/src/templates/mappings b/src/templates/mappings index cf2e82023..4f51a28bf 100644 --- a/src/templates/mappings +++ b/src/templates/mappings @@ -25,6 +25,7 @@ dropwhile.derived:org.python.modules.itertools.dropwhileDerived groupby.derived:org.python.modules.itertools.groupbyDerived ifilter.derived:org.python.modules.itertools.ifilterDerived ifilterfalse.derived:org.python.modules.itertools.ifilterfalseDerived +imap.derived:org.python.modules.itertools.imapDerived islice.derived:org.python.modules.itertools.isliceDerived izip.derived:org.python.modules.itertools.izipDerived izipLongest.derived:org.python.modules.itertools.izipLongestDerived @@ -54,6 +55,7 @@ partial.derived:org.python.modules._functools.PyPartialDerived property.derived:org.python.core.PyPropertyDerived random.derived:org.python.modules.random.PyRandomDerived set.derived:org.python.core.PySetDerived +shadowstr.derived:org.python.core.PyShadowStringDerived str.derived:org.python.core.PyStringDerived super.derived:org.python.core.PySuperDerived tuple.derived:org.python.core.PyTupleDerived @@ -61,6 +63,7 @@ type.derived:org.python.core.PyTypeDerived unicode.derived:org.python.core.PyUnicodeDerived weakref.derived:org.python.modules._weakref.ReferenceTypeDerived zipimporter.derived:org.python.modules.zipimport.zipimporterDerived +antlr.AST.derived:org.python.antlr.ASTDerived ast_Assert.derived:org.python.antlr.ast.AssertDerived ast_Assign.derived:org.python.antlr.ast.AssignDerived ast_Attribute.derived:org.python.antlr.ast.AttributeDerived @@ -101,6 +104,8 @@ ast_Print.derived:org.python.antlr.ast.PrintDerived ast_Raise.derived:org.python.antlr.ast.RaiseDerived ast_Repr.derived:org.python.antlr.ast.ReprDerived ast_Return.derived:org.python.antlr.ast.ReturnDerived +ast_Set.derived:org.python.antlr.ast.SetDerived +ast_SetComp.derived:org.python.antlr.ast.SetCompDerived ast_Slice.derived:org.python.antlr.ast.SliceDerived ast_Str.derived:org.python.antlr.ast.StrDerived ast_Subscript.derived:org.python.antlr.ast.SubscriptDerived @@ -153,3 +158,5 @@ op_USub.derived:org.python.antlr.op.USubDerived _io._IOBase.derived:org.python.modules._io.PyIOBaseDerived _io._RawIOBase.derived:org.python.modules._io.PyRawIOBaseDerived _io.FileIO.derived:org.python.modules._io.PyFileIODerived +_json.Encoder.derived:org.python.modules._json.EncoderDerived +_json.Scanner.derived:org.python.modules._json.ScannerDerived diff --git a/src/templates/shadowstr.derived b/src/templates/shadowstr.derived new file mode 100644 index 000000000..0d3874c48 --- /dev/null +++ b/src/templates/shadowstr.derived @@ -0,0 +1,5 @@ +base_class: PyShadowString +want_dict: true +ctr: PyObject str, PyObject shadow +incl: object +no_toString: true diff --git a/tests/data/initializer/META-INF/services/org.python.core.JythonInitializer b/tests/data/initializer/META-INF/services/org.python.core.JythonInitializer deleted file mode 100644 index fa58d98b4..000000000 --- a/tests/data/initializer/META-INF/services/org.python.core.JythonInitializer +++ /dev/null @@ -1 +0,0 @@ -SyspathAppendingInitializer diff --git a/tests/data/initializer/SyspathAppendingInitializer.java b/tests/data/initializer/SyspathAppendingInitializer.java deleted file mode 100644 index e0326ef37..000000000 --- a/tests/data/initializer/SyspathAppendingInitializer.java +++ /dev/null @@ -1,18 +0,0 @@ -import java.util.Properties; -import org.python.core.JythonInitializer; -import org.python.core.Py; -import org.python.core.PySystemState; -import org.python.core.adapter.ExtensiblePyObjectAdapter; - -public class SyspathAppendingInitializer implements JythonInitializer { - public void initialize(Properties preProperties, - Properties postProperties, - String[] argv, - ClassLoader classLoader, - ExtensiblePyObjectAdapter adapter) { - postProperties.put(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); - PySystemState defaultState = - PySystemState.doInitialize(preProperties, postProperties, argv, classLoader, adapter); - defaultState.path.append(Py.newString("/from_SyspathAppendingInitializer_with_love")); - } -} diff --git a/tests/java/javatests/Dict2JavaTest.java b/tests/java/javatests/Dict2JavaTest.java index aed22379d..cd284baa8 100644 --- a/tests/java/javatests/Dict2JavaTest.java +++ b/tests/java/javatests/Dict2JavaTest.java @@ -64,7 +64,7 @@ public boolean test_get_gd() { public boolean test_put_hig() { map.put("h", null); - map.put("i", new Integer(3)); + map.put("i", Integer.valueOf(3)); Object val = map.put("g", "3"); return val.equals("2"); } @@ -78,7 +78,7 @@ public boolean test_java_mapentry() { // Test a number hmap = new HashMap(); - hmap.put("i", new Integer(3)); + hmap.put("i", Integer.valueOf(3)); entry = hmap.entrySet().iterator().next(); if (!map.entrySet().contains(entry)) return false; @@ -95,7 +95,7 @@ public boolean test_java_mapentry() { public boolean test_entry_set_nulls() { Set> set = map.entrySet(); return set.contains(null) == false && set.remove(null) == false && - set.contains(new Boolean(true)) == false && set.remove(new String("")) == false; + set.contains(Boolean.TRUE) == false && set.remove(new String("")) == false; } diff --git a/tests/java/javatests/Issue1972.java b/tests/java/javatests/Issue1972.java index 63872f477..43b6ef8d2 100644 --- a/tests/java/javatests/Issue1972.java +++ b/tests/java/javatests/Issue1972.java @@ -289,7 +289,6 @@ public void jythonReadline() throws Exception { // Run Jython simple readline programme setProcJava( // "-Dpython.console=org.python.util.JLineConsole", // - // "-Dpython.console.interactive=True", // "-Dpython.home=" + pythonHome, // "org.python.util.jython", // "-c", // diff --git a/tests/java/javatests/Issue2455Test.java b/tests/java/javatests/Issue2455Test.java new file mode 100644 index 000000000..7a9da29c1 --- /dev/null +++ b/tests/java/javatests/Issue2455Test.java @@ -0,0 +1,94 @@ +package javatests; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.python.core.PyJavaPackage; +import org.python.core.PyModule; +import org.python.util.PythonInterpreter; + +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import static org.junit.Assert.*; + +/** + * Test for the Jython bug 2455. + * @author jsaiz + */ +public class Issue2455Test { + + private static final String NEW_LINE = System.getProperty("line.separator"); + + private final PythonInterpreter interpreter = new PythonInterpreter(); + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test(timeout = 60000) + public void testJavaModule() throws IOException, InterruptedException { + File example1 = temporaryFolder.newFolder("example1"); + File example2 = temporaryFolder.newFolder("example2"); + + // Create Java class in example1 and __init__.py in example2 + createJavaFile(example1, "SomeClass"); + createInitFile(example2); + + // Create an interpreter and import the example packages + interpreter.exec("import sys"); + interpreter.exec("sys.path.append('" + temporaryFolder.getRoot().toString() + "')"); + interpreter.exec("import " + example1.getName()); + interpreter.exec("import " + example2.getName()); + assertTrue(interpreter.eval(example1.getName()) instanceof PyJavaPackage); + assertTrue(interpreter.eval(example2.getName()) instanceof PyModule); + + // Now add a Java class to example2 (after importing; otherwise example2 might be loaded as a PyJavaPackage) + createJavaFile(example2, "OtherClass"); + + // Both classes should be found + evaluate(example1.getName() + ".SomeClass"); + evaluate(example2.getName() + ".OtherClass"); // works with 2.5.2 and the patch for 2.7.1, fails with 2.7.0 + } + + private void createJavaFile(File packageFolder, String className) throws IOException, InterruptedException { + String javaCode = "package " + packageFolder.getName() + ";" + NEW_LINE + "public class " + className + " {}" + NEW_LINE; + File javaFile = new File(packageFolder, className + ".java"); + createFile(javaFile, javaCode); + + compileJavaFile(javaFile); + } + + private void compileJavaFile(File javaFile) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); + + Iterable compilationUnits = + fileManager.getJavaFileObjectsFromFiles(new ArrayList<>(Arrays.asList(javaFile))); + compiler.getTask(null, fileManager, null, null, null, compilationUnits).call(); + } + + private void createInitFile(File directory) throws IOException { + File jythonFile = new File(directory, "__init__.py"); + createFile(jythonFile, "print 'within __init__.py'"); + } + + private void createFile(File file, String text) throws IOException { + file.getParentFile().mkdirs(); + try (FileWriter writer = new FileWriter(file)) { + writer.append(text); + writer.flush(); + } + } + + private void evaluate(String className) { + assertEquals("", interpreter.eval(className).toString()); + } +} diff --git a/tests/java/javatests/ListTest.java b/tests/java/javatests/ListTest.java index fd948f3a1..9f337d138 100644 --- a/tests/java/javatests/ListTest.java +++ b/tests/java/javatests/ListTest.java @@ -210,11 +210,11 @@ public void test_add_index() { a.add(i, b.get(i)); } try { - a.add(a.size() + 1, new Integer(a.size() + 1)); + a.add(a.size() + 1, Integer.valueOf(a.size() + 1)); TestSupport.fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) {} try { - a.add(-1, new Integer(-1)); + a.add(-1, Integer.valueOf(-1)); TestSupport.fail("expected IndexOutOfBoundsException"); } catch (IndexOutOfBoundsException e) {} } diff --git a/tests/java/ProxyDeserialization.java b/tests/java/javatests/ProxyDeserialization.java similarity index 88% rename from tests/java/ProxyDeserialization.java rename to tests/java/javatests/ProxyDeserialization.java index c8730a3fe..8c4aa773a 100644 --- a/tests/java/ProxyDeserialization.java +++ b/tests/java/javatests/ProxyDeserialization.java @@ -1,8 +1,8 @@ -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.concurrent.Callable; +package javatests; + import java.io.FileInputStream; import java.io.ObjectInputStream; +import java.util.concurrent.Callable; public class ProxyDeserialization { diff --git a/tests/java/javatests/Reflection.java b/tests/java/javatests/Reflection.java index 8d021b921..50ccb9d25 100644 --- a/tests/java/javatests/Reflection.java +++ b/tests/java/javatests/Reflection.java @@ -9,11 +9,34 @@ public class Reflection { + public static class BooleanVarargs { + + public String test(boolean... args) { + return "booleans...:" + Arrays.toString(args); + } + + public String testOneFixedArg(boolean arg1, boolean... args) { + return "boolean arg1:" + arg1 + " booleans...:" + Arrays.toString(args); + } + + public String testTwoFixedArg(boolean arg1, boolean arg2, boolean... args) { + return "boolean arg1:" + arg1 + " boolean arg2:" + arg2 + " booleans...:" + Arrays.toString(args); + } + } + public static class StringVarargs { public String test(String... args) { return "String...:" + Arrays.toString(args); } + + public String testOneFixedArg(String arg1, String... args) { + return "String arg1:" + arg1 + " String...:" + Arrays.toString(args); + } + + public String testTwoFixedArg(String arg1, String arg2, String... args) { + return "String arg1:" + arg1 + " String arg2:" + arg2 + " String...:" + Arrays.toString(args); + } } public static class ListVarargs { diff --git a/tests/java/org/python/compiler/JavaMakerSmokeTest.java b/tests/java/org/python/compiler/JavaMakerSmokeTest.java index 1814c8031..dca80ad90 100644 --- a/tests/java/org/python/compiler/JavaMakerSmokeTest.java +++ b/tests/java/org/python/compiler/JavaMakerSmokeTest.java @@ -12,6 +12,7 @@ import static org.junit.Assert.*; import org.python.core.PySystemState; +import org.python.core.RegistryKey; import org.python.util.PythonInterpreter; @@ -23,7 +24,7 @@ public class JavaMakerSmokeTest { @Before public void setUp() throws Exception { Properties props = new Properties(System.getProperties()); - props.setProperty(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); + props.setProperty(RegistryKey.PYTHON_CACHEDIR_SKIP, "true"); PySystemState.initialize(props, null); interp = new PythonInterpreter(); diff --git a/tests/java/org/python/core/BaseBytesTest.java b/tests/java/org/python/core/BaseBytesTest.java index 6d9d3bfbe..ac753b7a0 100644 --- a/tests/java/org/python/core/BaseBytesTest.java +++ b/tests/java/org/python/core/BaseBytesTest.java @@ -6,6 +6,7 @@ import junit.framework.TestCase; +import org.python.core.BaseBytes.Builder; import org.python.core.buffer.SimpleBuffer; import org.python.util.PythonInterpreter; @@ -217,7 +218,7 @@ public void testSize() { // Local constructor from byte[] int[] aRef = toInts("Chaque coquillage incrusté"); BaseBytes a = getInstance(aRef); - System.out.println(toString(a)); + // System.out.println(toString(a)); assertEquals(aRef.length, a.size()); // init(int) at various sizes @@ -237,7 +238,7 @@ public void testInit_intArray() { BaseBytes a = getInstance(aRef); // Copy constructor b = bytes(a) BaseBytes b = getInstance(a); - System.out.println(toString(b)); + // System.out.println(toString(b)); assertEquals(a.size(), b.size()); // assertEquals(a.storage, b.storage); // Supposed to share? // Check we got the same bytes @@ -254,7 +255,7 @@ public void testInit_Iterable() { // Make an Iterable of that Iterable ia = iterableBytes(aRef); BaseBytes a = getInstance(ia); - System.out.println(toString(a)); + // System.out.println(toString(a)); assertEquals(aRef.length, a.size()); checkInts(aRef, a); @@ -319,7 +320,7 @@ public void testInit_Exceptions() { PyObject aRef = boobyPrize[dip]; try { BaseBytes a = getInstance(brantub[dip]); - System.out.println(toString(a)); + // System.out.println(toString(a)); fail("Exception not thrown for " + brantub[dip]); } catch (PyException pye) { // System.out.println(pye); @@ -452,7 +453,7 @@ public void testPyset() { try { a.pyset(start, x); - System.out.println(toString(a)); + // System.out.println(toString(a)); fail(String.format("Exception not thrown for pyset(%d,%s)", start, x)); } catch (PyException pye) { // System.out.println(pye); @@ -476,7 +477,7 @@ public void testSetslice3() { try { a.setslice(start, stop, step, x); - System.out.println(toString(a)); + // System.out.println(toString(a)); fail(String.format("Exception not thrown for setslice(%d,%d,%d,%s)", start, stop, step, x)); } catch (PyException pye) { @@ -685,7 +686,7 @@ protected MyBytes(int start, int stop, BaseBytes source) { } /** - * Returns a PyByteArray that repeats this sequence the given number of times, as in the + * Returns a MyBytes that repeats this sequence the given number of times, as in the * implementation of __mul__ for strings. * * @param count the number of times to repeat this. @@ -693,9 +694,9 @@ protected MyBytes(int start, int stop, BaseBytes source) { */ @Override protected MyBytes repeat(int count) { - MyBytes ret = new MyBytes(); - ret.setStorage(repeatImpl(count)); - return ret; + Builder builder = new Builder(size * (long) count); + builder.repeat(this, count); + return getResult(builder); } /** @@ -743,23 +744,11 @@ protected MyBytes(Builder builder) { setStorage(builder.getStorage(), builder.getSize()); } - /* - * (non-Javadoc) - * - * @see org.python.core.BaseBytes#getBuilder(int) - */ @Override - protected Builder getBuilder(int capacity) { - // Return a Builder specialised for my class - return new Builder(capacity) { - - @Override - MyBytes getResult() { - // Create a MyBytes from the storage that the builder holds - return new MyBytes(this); - } - }; + protected MyBytes getResult(Builder b) { + return new MyBytes(b); } + } /** diff --git a/tests/java/org/python/core/ConcurrentTypeTest.java b/tests/java/org/python/core/ConcurrentTypeTest.java new file mode 100644 index 000000000..64f541654 --- /dev/null +++ b/tests/java/org/python/core/ConcurrentTypeTest.java @@ -0,0 +1,487 @@ +// Copyright (c)2019 Jython Developers +// Licensed to the PSF under a Contributor Agreement +package org.python.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.tools.FileObject; +import javax.tools.ForwardingJavaFileManager; +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import org.junit.Test; +import org.python.util.PythonInterpreter; + +/** + * Unit test exercising the import and type system from concurrent threads. Over the years, Jython + * has experienced multiple issues with respect to the management of types and import, in the + * presence of multiple threads and interpreters. It seems difficult to get this right. + *

    + * The initial version of this unit test was created in response to + * issue 2834. + */ +public class ConcurrentTypeTest { + + private static int RUNNERS = 100; + + static { + // Do not need site.py for test: makes more complicated in IDE. + Options.importSite = false; + } + + private abstract static class ScriptRunner implements Runnable { + + final int instance; + final Thread thread; + String script; + PyCode code; + final PyStringMap globals = Py.newStringMap(); + /** Sub-class constructor must assign the configured interpreter. */ + PythonInterpreter interp; + + ScriptRunner(int instance) { + this.instance = instance; + this.thread = new Thread(this); + this.globals.__setitem__("instance", Py.newInteger(instance)); + } + + /** Set the interpreter and compile the script. */ + void setInterp(PythonInterpreter interp, String script) { + this.interp = interp; + this.script = script; + this.code = interp.compile(script); + } + + @Override + public void run() { + interp.exec(code); + } + } + + /** + * Test concurrency when importing the same Java class where the interpreters all share a + * {@code PySystemState}. + */ + @Test + public void testSharedState() { + + // Make all the runners in advance. + List runners = new ArrayList<>(RUNNERS); + for (int i = 0; i < RUNNERS; i++) { + runners.add(new SharedStateRunner(javaImportScript, i)); + } + + // Start the runners then let all of them finish (or fail). + awaitAll(runners); + + // Check status of every thread + for (SharedStateRunner r : runners) { + PyObject e = r.globals.__finditem__("e"); + assertEquals("Runner " + r.instance, null, e); + } + } + + /** + * Script to import all names from a Java class for {@link #testSharedState()} and + * {@link #testSeparateState()}. + */ + //@formatter:off + static final String javaImportScript = String.join("\n", new String[] { + "try:", + " from javax.swing.text.Utilities import *", + " f = getNextWord", // May raise NameError + "except Exception as e:", + " pass" + }); + //@formatter:on + + /** + * Each instance of this type has its own {@link PythonInterpreter}, but they all share the same + * (default) {@code PySystemState} + */ + private static class SharedStateRunner extends ScriptRunner { + + SharedStateRunner(String script, int instance) { + super(instance); + setInterp(new PythonInterpreter(globals), script); + } + } + + /** + * Test concurrency when importing the same Java class where the interpreters all have their own + * {@code PySystemState}. At version 2.7.2b2, this test occasionally fails with a + * {@code NameError}, when the member {@code getNextWord} imported from + * {@code javax.swing.text.Utilities} is not found. The cause is thought to be a race between + * threads in {@code SysPackageManager}. It is necessary to run this test in the shell with + * something like:

    +     * PS jython-trunk> do {
    +     * >>   java -cp "build\exposed;build\classes;extlibs\*" org.junit.runner.JUnitCore org.python.core.ConcurrentTypeTest
    +     * >> } while ($LastExitCode -eq 0)
    +     * 
    Expect a hundred iterations or more before you see + * {@code "name 'getNextWord' is not defined"}. Suppress other tests in the suite. + * + */ + @Test + public void testSeparateState() { + + // Make all the runners in advance. + List runners = new ArrayList<>(RUNNERS); + for (int i = 0; i < RUNNERS; i++) { + runners.add(new SeparateStateRunner(javaImportScript, i)); + } + + // Start the runners then let all of them finish (or fail). + awaitAll(runners); + + // Check status of every thread + for (SeparateStateRunner r : runners) { + PyObject e = r.globals.__finditem__("e"); + assertEquals("Runner " + r.instance, null, e); + } + } + + /** + * Script to import all names from a Java class for {@link #testSharedState()} and + * {@link #testSeparateState()}. At version 2.7.2b2, this test frequently (not every time) fails + * with an {@code AttributeError}, when member {@code sleep} of {@code java.lang.Thread} is not + * found for the call. + */ + //@formatter:off + static final String javaImportScript2 = String.join("\n", new String[] { + "try:", + " from java.lang import Thread", + " Thread.sleep(instance*10)", // May raise AttributeError + " from javax.swing.text.Utilities import *", + " f = getNextWord", // May raise NameError + "except Exception as e:", + " pass" + }); + //@formatter:on + + /** + * Test concurrency when importing the same Java class where the interpreters all have their own + * {@code PySystemState}. It differs from {@link #testSeparateState()} in importing + * {@code Thread} add calling {@code Thread.sleep}. (The original idea was to provoke + * switching.) At version 2.7.2b2, this test fails about one time in 5 with an AttributeError, + * when the member {@code Thread.sleep} is not found. + */ + @Test + public void testSeparateState2() { + + // Make all the runners in advance. + List runners = new ArrayList<>(RUNNERS); + for (int i = 0; i < RUNNERS; i++) { + runners.add(new SeparateStateRunner(javaImportScript2, i)); + } + + // Start the runners then let all of them finish (or fail). + awaitAll(runners); + + // Check status of every thread + for (SeparateStateRunner r : runners) { + PyObject e = r.globals.__finditem__("e"); + assertEquals("Runner " + r.instance, null, e); + } + } + + /** + * Each instance of this type has its own {@code PySystemState}, as well as its own + * {@link PythonInterpreter}. + */ + private static class SeparateStateRunner extends ScriptRunner { + + final PySystemState sys = new PySystemState(); + + SeparateStateRunner(String script, int instance) { + super(instance); + setInterp(new PythonInterpreter(globals, sys), script); + } + } + + /** + * Test concurrency when importing the same Java class where the interpreters all have their own + * {@code ClassLoader}. In this variant we import * from Foo, and test the static members. + */ + @Test + public void testSeparateLoader() { + + // Compile the Java source and cache it in this file manager: */ + ClassCacheFileManager fileManager = getClassCacheFileManager(loadedJava, "Foo"); + + // Make all the runners in advance, primed with the same script. + List runners = new ArrayList<>(RUNNERS); + for (int i = 0; i < RUNNERS; i++) { + runners.add(new SeparateLoaderRunner(loaderScript, i, fileManager.newClassLoader())); + } + + // Start the runners then let all of them finish (or fail). + awaitAll(runners); + + // Check result of every thread + for (SeparateLoaderRunner r : runners) { + PyObject e = r.globals.__finditem__("e"); + assertEquals("Runner " + r.instance, null, e); + PyObject staticConstant = r.globals.__finditem__("staticConstant"); + assertNotNull(staticConstant); + assertEquals(staticConstant.asInt(), 42); + PyObject x = r.globals.__finditem__("x"); + assertEquals(x.asInt(), 42); + } + } + + /** + * A class defined in Java that is compiled as part of the tests {@link #testSeparateLoader()} + * and {@link #testSeparateLoader2()} and made available to Jython through a sp[ecific class + * loader. See {@link ClassCacheFileManager}. + */ + //@formatter:off + static final String loadedJava = String.join("\n", new String[] { + "package thin.air;", + "public class Foo {", + " public static final int staticConstant = 42;", + " public String member = \"forty-two\";", + " public static int staticMethod() { return 42; }", + " public String method() { return member; }", + "}" + }); + //@formatter:on + + /** + * Script to import all names from a Java class conjured from thin air (via class loader), used + * by {@link #testSeparateLoader()}. + */ + //@formatter:off + static final String loaderScript = String.join("\n", new String[] { + "try:", + " from thin.air.Foo import *", + " x = staticMethod()", + "except Exception as e:", + " pass" + }); + //@formatter:on + + /** + * Test concurrency when importing the same Java class where the interpreters all have their own + * {@code ClassLoader}. In this variant we import Foo, and instantiate one to test the instance + * members. + */ + @Test + public void testSeparateLoader2() { + + // Compile the Java source and cache it in this file manager: */ + ClassCacheFileManager fileManager = getClassCacheFileManager(loadedJava, "Foo"); + + // Make all the runners in advance, primed with the same script. + List runners = new ArrayList<>(RUNNERS); + for (int i = 0; i < RUNNERS; i++) { + runners.add(new SeparateLoaderRunner(loaderScript2, i, fileManager.newClassLoader())); + } + + // Start the runners then let all of them finish (or fail). + awaitAll(runners); + + // Check result of every thread + Set classes = new HashSet<>(); + Set types = new HashSet<>(); + + for (SeparateLoaderRunner r : runners) { + PyObject e = r.globals.__finditem__("e"); + assertEquals("Runner " + r.instance, null, e); + PyObject m = r.globals.__finditem__("m"); + assertEquals(m.toString(), "forty-two"); + PyObject x = r.globals.__finditem__("x"); + assertEquals(x.toString(), "forty-two"); + PyType f = (PyType) r.globals.__finditem__("Foo"); + types.add(f); + Object c = JyAttribute.getAttr(f, JyAttribute.JAVA_PROXY_ATTR); + classes.add(c); + } + + // XXX At the moment, these assertions fail (see https://bugs.jython.org/issue2834). + // assertEquals("Runners did not make a unique PyType Foo", runners.size(), types.size()); + // assertEquals("Runners did not load a unique Class Foo", runners.size(), classes.size()); + } + + /** + * Script to import a Java class conjured from thin air (via class loader). Used by + * {@link #testSeparateLoader2()} + */ + //@formatter:off + static final String loaderScript2 = String.join("\n", new String[] { + "try:", + " from thin.air import Foo", + " f = Foo()", + " m = f.member", + " x = f.method()", + "except Exception as e:", + " pass" + }); + //@formatter:on + + /** + * Each instance of this type has its own {@code ClassLoader}, as well as its own {@code sys} + * module and {@link PythonInterpreter}. + */ + private static class SeparateLoaderRunner extends ScriptRunner { + + final PySystemState sys = new PySystemState(); + + SeparateLoaderRunner(String script, int instance, ClassLoader classLoader) { + super(instance); + sys.setClassLoader(classLoader); + setInterp(new PythonInterpreter(globals, sys), script); + } + } + + /** + * A file manager that stores class files locally as byte arrays, for use with the Java compiler + * tool. + */ + private static class ClassCacheFileManager extends ForwardingJavaFileManager { + + final Map map; + + protected ClassCacheFileManager(JavaFileManager fileManager) { + super(fileManager); + this.map = new HashMap<>(); + } + + /** + * A {@code JavaFileObject} where writes go to an enclosed {@code ByteArrayOutputStream}, + * intended to capture a class definition. + */ + protected class ClassFileObject extends SimpleJavaFileObject { + + private final String className; + private ByteArrayOutputStream stream; + + ClassFileObject(String className) { + // JavaFileObject (superclass) requires a URI, so make up a protocol. + super(URI.create("map:///" + className), Kind.CLASS); + this.className = className; + } + + /** + * Create a stream that is cached in the map of the enclosing {@code FileManager} + * against the className given in the constructor, and provide it to the client for + * writing. + */ + @Override + public OutputStream openOutputStream() throws IOException { + // We'll store the bytes in an array. (It's elastic, but start with 1K.) + stream = new ByteArrayOutputStream(1024); + map.put(className, this); + return stream; + } + } + + @Override + public JavaFileObject getJavaFileForInput(Location location, String className, Kind kind) + throws IOException { + ClassFileObject file; + if (kind == Kind.CLASS && (file = map.get(className)) != null) { + return file; + } + return super.getJavaFileForInput(location, className, kind); + } + + @Override + public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, + FileObject sibling) throws IOException { + if (kind == Kind.CLASS) { + return new ClassFileObject(className); + } + return super.getJavaFileForOutput(location, className, kind, sibling); + } + + public ClassLoader newClassLoader() { + return new ClassLoader() { + + @Override + protected Class findClass(String className) throws ClassNotFoundException { + ClassFileObject file = map.get(className); + if (file != null) { + byte b[] = file.stream.toByteArray(); + return defineClass(className, b, 0, b.length); + } else { + throw new ClassNotFoundException(); + } + } + }; + } + } + + /** + * Helper to set up a compiled Java class in memory, to load through the apparatus defined + * above, for {@link #testSeparateLoader()}. + */ + private ClassCacheFileManager getClassCacheFileManager(final String javaSource, String name) { + // Compile Java class to import via loader. + final JavaCompiler COMPILER = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager stdFileManager = COMPILER.getStandardFileManager(null, null, null); + + // Get a String treated as a source file + JavaFileObject sourceFile = new SimpleJavaFileObject( + URI.create("string:///" + name + Kind.SOURCE.extension), Kind.SOURCE) { + + @Override + public CharSequence getCharContent(boolean ignore) { + return javaSource; + } + }; + Iterable compilationUnits = Collections.singletonList(sourceFile); + + // Arrange to catch the class definition file(s) in byte arrays. + ClassCacheFileManager fileManager = new ClassCacheFileManager(stdFileManager); + + // Create a task (future) to perform the compilation + CompilationTask task = + COMPILER.getTask(null, fileManager, null, null, null, compilationUnits); + assertTrue("Compilation of Java class failed", task.call()); + + return fileManager; + } + + /** Start each thread and wait for it to complete. */ + private void awaitAll(List runners) { + // Start the runners in their threads + for (ScriptRunner r : runners) { + r.thread.start(); + } + + // Wait for all the runners to finish (but don't wait forever) + boolean running = true; + for (int attempts = 0; running && attempts < 10; attempts++) { + running = false; + for (ScriptRunner r : runners) { + Thread t = r.thread; + try { + t.join(100); + } catch (InterruptedException e) {/* meh */} + running |= t.isAlive(); + } + } + assertFalse("runners did not finish", running); + } +} diff --git a/tests/java/org/python/core/PyBufferTest.java b/tests/java/org/python/core/PyBufferTest.java index 023a6c59c..1cee5483d 100644 --- a/tests/java/org/python/core/PyBufferTest.java +++ b/tests/java/org/python/core/PyBufferTest.java @@ -60,7 +60,7 @@ public class PyBufferTest { protected int verbosity = 0; /** Print a list of the test material. (From JUnit 4.12 use Parameters(name)). */ - protected static final boolean PRINT_KEY = true; + protected static final boolean PRINT_KEY = false; /** Size of some large arrays. */ static final int LONG = 1000; diff --git a/tests/java/org/python/core/PyByteArrayTest.java b/tests/java/org/python/core/PyByteArrayTest.java index 8d537aded..d65803794 100644 --- a/tests/java/org/python/core/PyByteArrayTest.java +++ b/tests/java/org/python/core/PyByteArrayTest.java @@ -12,6 +12,9 @@ */ public class PyByteArrayTest extends BaseBytesTest { + /** This program may be used to display operation time, but this is not necessary for tests. */ + final static boolean SHOW_OPERATION_TIMES = false; + /** * Constructor required by JUnit. * @@ -963,11 +966,13 @@ public void test__setslice__3() { * slice to replace is simple and contiguous (2-argument slice). */ public void testSetsliceTime() { - int verbose = 1; - timeSetslice(50, 100, SMALL, 2 * SMALL, verbose); - timeSetslice(50, 100, MEDIUM, MEDIUM, verbose); - timeSetslice(500, 20, LARGE, LARGE / 5, verbose); - // timeSetslice(1000, 4, HUGE, HUGE/5, verbose); + if (SHOW_OPERATION_TIMES) { + int verbose = 1; + timeSetslice(50, 100, SMALL, 2 * SMALL, verbose); + timeSetslice(50, 100, MEDIUM, MEDIUM, verbose); + timeSetslice(500, 20, LARGE, LARGE / 5, verbose); + timeSetslice(1000, 4, HUGE, HUGE/5, verbose); + } } /** @@ -1388,11 +1393,13 @@ public void test__delslice__3() { * slice to replace is extended (3-argument slice). */ public void testDelsliceTime3() { - int verbose = 1; - timeDelslice3(50, 100, SMALL, verbose); - timeDelslice3(50, 100, MEDIUM, verbose); - timeDelslice3(20, 4, LARGE, verbose); - // timeDelslice3(10, 1, HUGE, verbose); + if (SHOW_OPERATION_TIMES) { + int verbose = 1; + timeDelslice3(50, 100, SMALL, verbose); + timeDelslice3(50, 100, MEDIUM, verbose); + timeDelslice3(20, 4, LARGE, verbose); + timeDelslice3(10, 1, HUGE, verbose); + } } /** diff --git a/tests/java/org/python/core/PySystemStateTest.java b/tests/java/org/python/core/PySystemStateTest.java index 4e1ff9f4f..ff37030f6 100644 --- a/tests/java/org/python/core/PySystemStateTest.java +++ b/tests/java/org/python/core/PySystemStateTest.java @@ -1,74 +1,175 @@ package org.python.core; +import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; -import junit.framework.TestCase; +import org.python.util.PythonInterpreter; import jnr.posix.util.Platform; -import org.python.util.PythonInterpreter; +import junit.framework.TestCase; public class PySystemStateTest extends TestCase { + /** + * A class to hold examples of URLs (just the path and class noise) and the reference answer. + * Provide the reference answer like a Un*x path (forward slash). + */ + private static class JarExample { + + final String urlJarPath; + final String urlClassPath; + final String filePath; + + /** This constructor adapts unixPath to Windows when on Windows. */ + JarExample(String urlJarPath, String urlClassPath, String unixPath) { + this(urlJarPath, urlClassPath, + Platform.IS_WINDOWS ? new File(unixPath).toString() : unixPath, true); + } + + /** This constructor accepts filePath exactly as given. */ + JarExample(String urlJarPath, String urlClassPath, String filePath, boolean ignored) { + this.urlJarPath = urlJarPath; + this.urlClassPath = urlClassPath; + this.filePath = filePath; + } + } + + /** + * Examples of URLs (just the path and class noise) and the reference answer. Provide the + * reference answer like a Un*x path (forward slash). + */ + private static List jarExamples = Arrays.asList(// + // simple jar-file url + new JarExample("/some_dir/some.jar", "a/package/with/A.class", "/some_dir/some.jar"), + // jar-file url to decode + new JarExample("/some%20dir/some.jar", "a/package/with/A.class", "/some dir/some.jar"), + // In an old implementation using URLDecoder "+" needed special treatment + new JarExample("/some+dir/some.jar", "a/package/with/A.class", "/some+dir/some.jar"), + // Some characters should be encoded in the URL, but emerge as themselves in the path. + new JarExample("/n%c3%a5gon/katalog/r%c3%a4tt.jar", "en/f%c3%b6rpackning/med/En.class", + "/någon/katalog/rätt.jar") // + ); + + /* Check drive-letter and UNC path handling if on Windows. */ + static { + if (Platform.IS_WINDOWS) { + // Add some examples to the list (must be made mutable for that). + jarExamples = new ArrayList(jarExamples); + + // Drive-letter examples + jarExamples.add(new JarExample("/C:/some_dir/some.jar", "a/package/with/A.class", + "C:\\some_dir\\some.jar", true)); + jarExamples.add(new JarExample("/E:/n%c3%a5gon/katalog/r%c3%a4tt.jar", "med/En.class", + "E:\\någon\\katalog\\rätt.jar", true)); + + // Simple network file path (UNC path without controversial characters) + String p = "/org/python/version.properies"; + String r = "\\\\localhost\\shared\\jython-dev.jar"; + // JAR UNC file resource URL as produced by File.getURL or getURI + jarExamples.add(new JarExample("////localhost/shared/jython-dev.jar", p, r, true)); + // JAR UNC file resource URL as produced by URLClassLoader.getResource + jarExamples.add(new JarExample("//localhost/shared/jython-dev.jar", p, r, true)); + + // Network file path (UNC path with a controversial characters) + r = "\\\\localhost\\shared\\jy thon%dev.jar"; + // JAR UNC file resource URL based on (deprecated) File.getURL is invalid + // jarExamples.add(new JarExample("//localhost/shared/jy thon%dev.jar", p, r, true)); + // JAR UNC file resource URL based on File.getURI + jarExamples.add(new JarExample("////localhost/shared/jy%20thon%25dev.jar", p, r, true)); + // JAR UNC file resource URL as produced by URLClassLoader.getResource + jarExamples.add(new JarExample("//localhost/shared/jy%20thon%25dev.jar", p, r, true)); + } + } + + /** + * Test case for finding the path in the local file system of the file located by a JAR-file + * URL. A URL is a sequence of characters (from a limited set) that encodes a sequence of octets + * that may (if the protocol intends it) represent characters in some encoding. In the case of a + * JAR-file URL, these octets encode the file path elements in UTF-8. + */ public void testGetJarFileNameFromURL() throws Exception { // null assertNull(Py.getJarFileNameFromURL(null)); - // plain jar url - String urlString = "jar:file:/some_dir/some.jar!/a/package/with/A.class"; - URL url = new URL(urlString); - assertEquals("/some_dir/some.jar", Py.getJarFileNameFromURL(url)); - // jar url to decode - urlString = "jar:file:/some%20dir/some.jar!/a/package/with/A.class"; - url = new URL(urlString); - assertEquals("/some dir/some.jar", Py.getJarFileNameFromURL(url)); - // jar url with + signs to escape - urlString = "jar:file:/some+dir/some.jar!/a/package/with/A.class"; - url = new URL(urlString); - assertEquals("/some+dir/some.jar", Py.getJarFileNameFromURL(url)); + // Examples from the table + for (JarExample ex : jarExamples) { + // Something like jar:file:/some_dir/some.jar!/a/package/with/A.class + URL url = new URL("jar:file:" + ex.urlJarPath + "!/" + ex.urlClassPath); + assertEquals(ex.filePath, Py.getJarFileNameFromURL(url)); + } } + /** + * Test case for finding the path in the local file system of the file located by a JBoss vfszip + * URL. This is problematic as an objective because a path in the VFS does not necessarily have + * a counterpart in the local file system. However, the implementation and test are based on + * behaviour observed when this is the case. + */ public void testGetJarFileNameFromURL_jboss() throws Exception { final String protocol = "vfszip"; final String host = ""; final int port = -1; final URLStreamHandler handler = new TestJBossURLStreamHandler(); + // Test with any class file in org.python.core + final String classPart = "/org/python/core/PySystemState.class"; String file; URL url; if (Platform.IS_WINDOWS) { // plain jboss url - file = "/C:/some_dir/some.jar/org/python/core/PySystemState.class"; + file = "/C:/some_dir/some.jar" + classPart; url = new URL(protocol, host, port, file, handler); // tests with jboss on windows gave URL's like this: - assertEquals("vfszip:/C:/some_dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("C:/some_dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/C:/some_dir/some.jar" + classPart, url.toString()); + String result = Py.getJarFileNameFromURL(url); + assertEquals("C:\\some_dir\\some.jar", result); // jboss url to decode - file = "/C:/some%20dir/some.jar/org/python/core/PySystemState.class"; + file = "/C:/some%20dir/some.jar" + classPart; url = new URL(protocol, host, port, file, handler); - assertEquals("vfszip:/C:/some%20dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("C:/some dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/C:/some%20dir/some.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("C:\\some dir\\some.jar", result); // jboss url with + to escape - file = "/C:/some+dir/some.jar/org/python/core/PySystemState.class"; + file = "/C:/some+dir/some.jar" + classPart; url = new URL(protocol, host, port, file, handler); - assertEquals("vfszip:/C:/some+dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("C:/some+dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/C:/some+dir/some.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("C:\\some+dir\\some.jar", result); + // jboss url with challenging JAR name (assume will be provided RFC-2396 encoded) + file = "/C:/n%c3%a5gon/katalog/r%c3%a4tt.jar" + classPart; + url = new URL(protocol, host, port, file, handler); + assertEquals("vfszip:/C:/n%c3%a5gon/katalog/r%c3%a4tt.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("C:\\någon\\katalog\\rätt.jar", result); } else { // plain jboss url - file = "/some_dir/some.jar/org/python/core/PySystemState.class"; + file = "/some_dir/some.jar" + classPart; url = new URL(protocol, host, port, file, handler); - assertEquals("vfszip:/some_dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("/some_dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/some_dir/some.jar" + classPart, url.toString()); + String result = Py.getJarFileNameFromURL(url); + assertEquals("/some_dir/some.jar", result); // jboss url to decode - file = "/some%20dir/some.jar/org/python/core/PySystemState.class"; + file = "/some dir/some.jar" + classPart; url = new URL(protocol, host, port, file, handler); - assertEquals("vfszip:/some%20dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("/some dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/some%20dir/some.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("/some dir/some.jar", result); // jboss url with + to escape - file = "/some+dir/some.jar/org/python/core/PySystemState.class"; + file = "/some+dir/some.jar" + classPart; + url = new URL(protocol, host, port, file, handler); + assertEquals("vfszip:/some+dir/some.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("/some+dir/some.jar", result); + // jboss url with challenging JAR name (assume will be provided RFC-2396 encoded) + file = "/n%c3%a5gon/katalog/r%c3%a4tt.jar" + classPart; url = new URL(protocol, host, port, file, handler); - assertEquals("vfszip:/some+dir/some.jar/org/python/core/PySystemState.class", url.toString()); - assertEquals("/some+dir/some.jar", Py.getJarFileNameFromURL(url)); + assertEquals("vfszip:/n%c3%a5gon/katalog/r%c3%a4tt.jar" + classPart, url.toString()); + result = Py.getJarFileNameFromURL(url); + assertEquals("/någon/katalog/rätt.jar", result); } } @@ -85,6 +186,12 @@ public void testImport() throws Exception { } } + /** + * A URL handler that emulates the behaviour (as far as we're concerned) of + * {@code org.jboss.virtual.protocol.vfs.Handler}, that we can use to make URLs that behave the + * same way as JBoss ones. + * + */ protected static class TestJBossURLStreamHandler extends URLStreamHandler { @Override diff --git a/tests/java/org/python/core/packagecache/CachedJarsOver64kTest.java b/tests/java/org/python/core/packagecache/CachedJarsOver64kTest.java index 01f01d411..5b1237771 100644 --- a/tests/java/org/python/core/packagecache/CachedJarsOver64kTest.java +++ b/tests/java/org/python/core/packagecache/CachedJarsOver64kTest.java @@ -41,7 +41,7 @@ public TestCachePackageManager(File cachedir) { } @Override - protected void warning(String msg){ + protected void warning(String msg, Object... params) { failed = true; } diff --git a/tests/java/org/python/expose/generate/DescriptorExposerTest.java b/tests/java/org/python/expose/generate/DescriptorExposerTest.java index 2ce1817b5..5a1bccdc8 100644 --- a/tests/java/org/python/expose/generate/DescriptorExposerTest.java +++ b/tests/java/org/python/expose/generate/DescriptorExposerTest.java @@ -33,7 +33,7 @@ public PyDataDescr makeDescriptor(DescSetup setup, String name) throws Exception DescriptorExposer de = new DescriptorExposer(ASM_TYPE, name); setup.setup(de); Class descriptor = de.load(new BytecodeLoader.Loader()); - PyDataDescr descr = (PyDataDescr)descriptor.newInstance(); + PyDataDescr descr = (PyDataDescr)descriptor.getDeclaredConstructor().newInstance(); descr.setType(PY_TYPE); return descr; } diff --git a/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java b/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java index 79d5e5eab..342f1d499 100644 --- a/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java +++ b/tests/java/org/python/expose/generate/ExposeMethodFinderTest.java @@ -16,7 +16,7 @@ private ExposedMethodFinder makeFinder(int access, String descriptor, String met methodName, descriptor, null, - new MethodVisitor(Opcodes.ASM4) {}) { + new MethodVisitor(Opcodes.ASM7) {}) { @Override public void handleResult(InstanceMethodExposer exposer) { diff --git a/tests/java/org/python/expose/generate/ExposedTypeProcessorTest.java b/tests/java/org/python/expose/generate/ExposedTypeProcessorTest.java index c373bb2bb..1d1ba3f98 100644 --- a/tests/java/org/python/expose/generate/ExposedTypeProcessorTest.java +++ b/tests/java/org/python/expose/generate/ExposedTypeProcessorTest.java @@ -35,11 +35,11 @@ public void testDetectType() throws Exception { ice.getTypeExposer().load(loader); Class doctoredSimple = loader.loadClassFromBytes("org.python.expose.generate.SimpleExposed", ice.getBytecode()); - PyObject simp = (PyObject)doctoredSimple.newInstance(); + PyObject simp = (PyObject)doctoredSimple.getDeclaredConstructor().newInstance(); PyBuiltinCallable func = MethodExposerTest.instantiate(simple_method, "invisible"); PyBuiltinCallable bound = func.bind(simp); bound.__call__(); - PyDataDescr desc = (PyDataDescr)tostringDesc.newInstance(); + PyDataDescr desc = (PyDataDescr)tostringDesc.getDeclaredConstructor().newInstance(); desc.setType(simp.getType()); assertEquals(doctoredSimple.getField("toStringVal").get(simp), desc.__get__(simp, PyType.fromClass(doctoredSimple)).toString()); diff --git a/tests/java/org/python/expose/generate/InterpTestCase.java b/tests/java/org/python/expose/generate/InterpTestCase.java index 280c0479e..67c761f50 100644 --- a/tests/java/org/python/expose/generate/InterpTestCase.java +++ b/tests/java/org/python/expose/generate/InterpTestCase.java @@ -2,6 +2,7 @@ import org.python.core.Py; import org.python.core.PySystemState; +import org.python.core.RegistryKey; import junit.framework.TestCase; @@ -11,7 +12,7 @@ public abstract class InterpTestCase extends TestCase { public void setUp() throws Exception { - System.setProperty(PySystemState.PYTHON_CACHEDIR_SKIP, "true"); + System.setProperty(RegistryKey.PYTHON_CACHEDIR_SKIP, "true"); PySystemState.initialize(); } } diff --git a/tests/java/org/python/expose/generate/NewExposerTest.java b/tests/java/org/python/expose/generate/NewExposerTest.java index 6496e6054..156649a5e 100644 --- a/tests/java/org/python/expose/generate/NewExposerTest.java +++ b/tests/java/org/python/expose/generate/NewExposerTest.java @@ -22,7 +22,7 @@ public void testSimple() throws Exception { assertEquals("org.python.expose.generate.NewExposerTest$Instantiable$exposed___new__", ne.getClassName()); Class descriptor = ne.load(new BytecodeLoader.Loader()); - PyNewWrapper instance = (PyNewWrapper)descriptor.newInstance(); + PyNewWrapper instance = (PyNewWrapper)descriptor.getDeclaredConstructor().newInstance(); instance.setWrappedType(PyType.fromClass(Instantiable.class)); assertSame("__new__", instance.__getattr__("__name__").toString()); assertEquals(Py.One, instance.__call__(PyType.fromClass(Instantiable.class))); diff --git a/tests/java/org/python/expose/generate/OverridableNewExposerTest.java b/tests/java/org/python/expose/generate/OverridableNewExposerTest.java index c97049994..9cf63f7c9 100644 --- a/tests/java/org/python/expose/generate/OverridableNewExposerTest.java +++ b/tests/java/org/python/expose/generate/OverridableNewExposerTest.java @@ -23,7 +23,7 @@ public void setUp() throws Exception { Type.getMethodDescriptor(VOID, new Type[] {APYOBJ, ASTRING}), new String[] {}); Class descriptor = ne.load(new BytecodeLoader.Loader()); - instance = (PyNewWrapper)descriptor.newInstance(); + instance = (PyNewWrapper)descriptor.getDeclaredConstructor().newInstance(); type = PyType.fromClass(Instantiable.class); instance.setWrappedType(type); } diff --git a/tests/java/org/python/jsr223/ScriptEngineTest.java b/tests/java/org/python/jsr223/ScriptEngineTest.java index 2ed873308..eb97ecaba 100644 --- a/tests/java/org/python/jsr223/ScriptEngineTest.java +++ b/tests/java/org/python/jsr223/ScriptEngineTest.java @@ -15,12 +15,13 @@ import javax.script.ScriptException; import javax.script.SimpleScriptContext; -import junit.framework.TestCase; - import org.junit.Assert; import org.python.core.Options; +import org.python.core.PyList; import org.python.core.PyString; +import junit.framework.TestCase; + public class ScriptEngineTest extends TestCase { public void testEvalString() throws ScriptException { @@ -160,25 +161,37 @@ public void testBindings() throws ScriptException { assertNull(pythonEngine.get("x")); } - class ThreadLocalBindingsTest implements Runnable { + static class ThreadLocalBindingsTest implements Runnable { ScriptEngine engine; + int value; Object x; + Object name; Throwable exception; - public ThreadLocalBindingsTest(ScriptEngine engine) { + public ThreadLocalBindingsTest(ScriptEngine engine, int value) { this.engine = engine; + this.value = value; } + //@formatter:off + static final String script = String.join("\n", new String[] { + "try:", + " a", + "except NameError:", + " pass", + "else:", + " raise Exception('a is defined', a)"}); + //@formatter:on + @Override public void run() { try { Bindings bindings = engine.createBindings(); - assertNull(engine.eval( - "try: a\nexcept NameError: pass\nelse: raise Exception('a is defined', a)", - bindings)); - bindings.put("x", -7); + assertNull(engine.eval(script, bindings)); + bindings.put("x", value); x = engine.eval("x", bindings); + name = engine.eval("__name__", bindings); } catch (Throwable e) { e.printStackTrace(); exception = e; @@ -186,6 +199,13 @@ public void run() { } } + /** + * Test that, with the use of a {@code Bindings} argument to {@code ScriptEngine.eval}, the + * interpreter is presented with a distinct name space, whether in a thread or not, and + * that __name__ == "__main__" in the engine-scoped name space (only). + * + * @throws Exception + */ public void testThreadLocalBindings() throws ScriptException, InterruptedException { ScriptEngineManager manager = new ScriptEngineManager(); ScriptEngine pythonEngine = manager.getEngineByName("python"); @@ -193,15 +213,27 @@ public void testThreadLocalBindings() throws ScriptException, InterruptedExcepti pythonEngine.put("a", 42); pythonEngine.put("x", 15); - ThreadLocalBindingsTest test = new ThreadLocalBindingsTest(pythonEngine); - Thread thread = new Thread(test); - thread.run(); - thread.join(); + // Examine name space of the engine with Bindings + ThreadLocalBindingsTest test = new ThreadLocalBindingsTest(pythonEngine, -7); + test.run(); // This does not start a thread assertNull(test.exception); assertEquals(-7, test.x); + assertEquals("__builtin__", test.name); + + // Examine name space of the engine with Bindings and in a thread + ThreadLocalBindingsTest test2 = new ThreadLocalBindingsTest(pythonEngine, -22); + Thread thread = new Thread(test2); + thread.start(); // This *does* start a thread + thread.join(); + assertNull(test2.exception); + assertEquals(-22, test2.x); + assertEquals("__builtin__", test2.name); + + // Test name space of the pythonEngine without Bindings is unaffected assertEquals(15, pythonEngine.get("x")); assertNull(pythonEngine.eval("del x")); assertNull(pythonEngine.get("x")); + assertEquals("__main__", pythonEngine.eval("__name__")); } public void testInvoke() throws ScriptException, NoSuchMethodException { @@ -295,9 +327,10 @@ public void testScope_iter() throws ScriptException { ScriptEngine pythonEngine = manager.getEngineByName("python"); pythonEngine.eval("a = 4"); pythonEngine.eval("b = 'hi'"); - assertEquals( - "['__builtins__', 'a', 'b']", - pythonEngine.eval("repr(sorted((item for item in locals())))")); + PyList locals = (PyList) pythonEngine.eval("sorted((item for item in locals()))"); + Assert.assertTrue(locals.contains("a")); + Assert.assertTrue(locals.contains("b")); + Assert.assertTrue(locals.contains("__name__")); } public void testScope_lookup() throws ScriptException { diff --git a/tests/java/org/python/modules/_locale/_localeTest.java b/tests/java/org/python/modules/_locale/_localeTest.java new file mode 100644 index 000000000..b182b2ca0 --- /dev/null +++ b/tests/java/org/python/modules/_locale/_localeTest.java @@ -0,0 +1,626 @@ +// (c) 2019 Jython Developers +// Licensed to PSF under a contributor agreement + +package org.python.modules._locale; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.python.core.RegistryKey.PYTHON_LOCALE_CONTROL; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.NumberFormat; +import java.util.Locale; + +import org.junit.Before; +import org.junit.Test; +import org.python.core.Py; +import org.python.core.PyCode; +import org.python.core.PyDictionary; +import org.python.core.PyException; +import org.python.core.PyInteger; +import org.python.core.PyObject; +import org.python.core.PySet; +import org.python.core.PyString; +import org.python.core.PyStringMap; +import org.python.core.PySystemState; +import org.python.core.PyUnicode; +import org.python.util.PythonInterpreter; + +public class _localeTest { + + private PySystemState systemState; + private PythonInterpreter interp; + + @Before + public void setUp() throws Exception { + // Initialise a Jython interpreter + systemState = Py.getSystemState(); + interp = new PythonInterpreter(new PyStringMap(), systemState); + } + + @SuppressWarnings("static-access") + private void setLocaleProperty(String value) { + systemState.registry.setProperty(PYTHON_LOCALE_CONTROL, value); + } + + private void defaultState() { + setLocaleProperty(""); + } + + private void jython2LegacyState() { + setLocaleProperty("jython2_legacy"); + } + + private void settableState() { + setLocaleProperty("settable"); + } + + private void importAndInit() { + interp.exec("import _locale"); + /* + * Following line is a hacky workaround, because interpreter and PySystemState can't be + * fully reinitialized. classDictInit() is called implicitly on first module import only. + */ + interp.exec("_locale.classDictInit({})"); + } + + private void settableInit() { + settableState(); + importAndInit(); + } + + private void assertPyTrue(String variableName) { + PyObject result = interp.get(variableName); + assertEquals(Py.True, result); + } + + private void assertPyEquals(int expected, String valueName) { + PyObject result = interp.get(valueName); + assertEquals(new PyInteger(expected), result); + } + + private void assertPyEquals(String expected, String valueName) { + PyObject result = interp.get(valueName); + assertEquals(new PyString(expected), result); + } + + private void assertInterpEquals(String expected, String value) { + PyObject result1 = interp.get(expected); + PyObject result2 = interp.get(value); + assertEquals(result1, result2); + } + + @Test + public void moduleImportSettable() { + settableInit(); + PyObject _localeModule = interp.get("_locale"); + assertNotNull(_localeModule); + } + + @Test(expected = PyException.class) + public void moduleImportLegacy() { + jython2LegacyState(); + importAndInit(); + } + + @Test(expected = PyException.class) + public void moduleImportDefault() { + defaultState(); + importAndInit(); + } + + private static int javaMajorVersion() { + String versionString = System.getProperty("java.runtime.version"); + String[] javaVersionElements = versionString.split("\\.|_|-b"); + int major = Integer.valueOf(javaVersionElements[0]); + int minor = Integer.valueOf(javaVersionElements[1]); + if (major == 1) { + return minor; + } + return major; + } + + public void setLocaleEN_US(String tag) { + // Anchor test to a popular locale to prove alignment + settableInit(); + /* + * Java 8 and Python use en-US negative currency formatting ($123). This changes to -$123 + * from 9 onwards. + */ + int nSignPosition = 0; + if (javaMajorVersion() >= 9) { + nSignPosition = 1; + } + // @formatter:off + String script = + "from _locale import setlocale, localeconv\n" + + "setlocale(_locale.LC_ALL, '" + tag + "' ) \n" + + "expected = " + + "{'mon_decimal_point': '.', 'int_frac_digits': 2, " + + " 'p_sep_by_space': 0, 'frac_digits': 2, " + + " 'thousands_sep': ',', " + + " 'n_sign_posn': " + String.valueOf(nSignPosition) + " , " + + "'decimal_point': '.', 'int_curr_symbol': 'USD', " + + "'n_cs_precedes': 1, 'p_sign_posn': 3, " + + "'mon_thousands_sep': ',', 'negative_sign': '-', " + + "'currency_symbol': '$', 'n_sep_by_space': 0 , " + + "'positive_sign': '', 'p_cs_precedes': 1 } \n" + + "actual = localeconv() \n" + + "grouping = actual.pop('grouping',None) \n" + + "mon_grouping = actual.pop('mon_grouping',None) \n" + + "result = set( actual.items() ) ^ set(expected.items()) \n" + + "resultGrouping = (grouping == [3,0] ) \n" + + "resultMonGrouping = (mon_grouping == [3,0] ) \n"; + // @formatter:on + interp.exec(script); + PyObject result = interp.get("result"); + assertEquals(new PySet(), result); + assertPyTrue("resultGrouping"); + assertPyTrue("resultMonGrouping"); + } + + @Test + public void setLocaleEN_US_Underscore() { + /* + * Locales are aliased to underscore equivalents, due to that being a common convention in + * Python and Java itself. + */ + setLocaleEN_US("en_US.ISO8859-1"); + } + + @Test + public void setLocaleEN_US_Dash() { + setLocaleEN_US("en-US"); + } + + @Test + public void setLocaleEN_US_Tuple() { + settableInit(); + // @formatter:off + String script = + "from locale import setlocale, getlocale, LC_ALL \n" + + "setlocale(LC_ALL,('en-US','ISO8859-1') ) \n" + + "actual = getlocale() \n" + + "expected = ('en_US', 'ISO8859-1') \n"; + // @formatter:on + PyCode code = interp.compile(script); + interp.exec(code); + assertInterpEquals("expected", "actual"); + } + + @Test + public void setLocaleNotLCALL() { + settableInit(); + String script = "import locale \n" + "caught = False \n" + "try: \n" + + " locale.setlocale(locale.LC_MONETARY,'zh-CN') \n" + + "except locale.Error as e: \n" + " caught = True \n"; + // @formatter:on + interp.exec(script); + assertPyTrue("caught"); + } + + @Test + public void setLocaleEmpty() { + settableInit(); + // @formatter:off + String script = + "from _locale import setlocale \n" + + "setlocale(_locale.LC_ALL,'zh_CN.UTF-8') \n" + + "result1 = setlocale(_locale.LC_ALL) \n" + + "result2 = setlocale(_locale.LC_MONETARY,None) \n" + + "result3 = setlocale(_locale.LC_MONETARY,'zh_CN.UTF-8') \n"; + interp.exec(script); + assertPyEquals("zh_CN.UTF-8", "result1"); + assertPyEquals("zh_CN.UTF-8", "result2"); + assertPyEquals("zh_CN.UTF-8", "result3"); + } + + @Test + public void setLocaleDefault() { + settableInit(); + // @formatter:off + String script = + "from locale import setlocale \n" + + "result1 = setlocale(_locale.LC_ALL,'zh_CN.UTF-8') \n" + + "result2 = setlocale(_locale.LC_ALL,'') "; + // @formatter:on + interp.exec(script); + assertPyEquals("zh_CN.UTF-8", "result1"); + assertPyEquals(Locale.getDefault().toString() + "." + Charset.defaultCharset().name(), + "result2"); + } + + @Test(expected = PyException.class) + public void setLocaleInvalid() { + settableInit(); + // @formatter:off + String script = + "from _locale import setlocale \n" + + "result = setlocale(_locale.LC_ALL,'green_midget_cafe_nosuch') \n"; + // @formatter:on + interp.exec(script); + } + + @Test + public void setLocaleGerman() { + settableInit(); + // @formatter:off + String script = + "from _locale import setlocale, localeconv\n" + + "setlocale(_locale.LC_ALL,'de_DE.ISO8859-15') \n" + + "expected = " + + "{'mon_decimal_point': ',', 'int_frac_digits': 2, " + + " 'p_sep_by_space': 1, 'frac_digits': 2, " + + "'thousands_sep': '.', 'n_sign_posn': 1, " + + "'decimal_point': ',', 'int_curr_symbol': 'EUR', " + + "'n_cs_precedes': 0, 'p_sign_posn': 3, " + + "'mon_thousands_sep': '.', 'negative_sign': '-', " + + "'currency_symbol': '\\xa4' , 'n_sep_by_space': 1, " + + "'p_cs_precedes': 0, 'positive_sign': ''} \n" + + "actual = localeconv() \n" + + "grouping = actual.pop('grouping',None) \n" + + "mon_grouping = actual.pop('mon_grouping',None) \n" + + "result = set( actual.items() ) ^ set(expected.items()) \n" + + "resultGrouping = (grouping == [3,0] ) \n" + + "resultMonGrouping = (mon_grouping == [3,0] ) \n"; + // @formatter:on + PyCode code = interp.compile(script); + interp.exec(code); + PyObject result = interp.get("result"); + assertEquals(new PySet(), result); + assertPyTrue("resultGrouping"); + assertPyTrue("resultMonGrouping"); + } + + @Test + public void setLocaleChinaMainland() { + settableInit(); + /* + * Java has ¥ \uffe5 rather than 元 \u5143 for zh-CN Java has negative sign preceding, Python + * following. + */ + // @formatter:off + String script = + "from _locale import setlocale, localeconv\n" + + "setlocale(_locale.LC_ALL,'zh_CN.UTF-8') \n" + + "expected = " + + "{'mon_decimal_point': '.', 'int_frac_digits': 2, " + + " 'p_sep_by_space': 0, 'frac_digits': 2, " + + "'thousands_sep': ',', 'n_sign_posn': 1, " + + "'decimal_point': '.', 'int_curr_symbol': 'CNY', " + + "'n_cs_precedes': 1, 'p_sign_posn': 3, " + + "'mon_thousands_sep': ',', 'negative_sign': '-', " + + "'currency_symbol': '\\xef\\xbf\\xa5' , " + + "'n_sep_by_space': 0, " + + "'p_cs_precedes': 1, 'positive_sign': ''} \n" + + "actual = localeconv() \n" + + "grouping = actual.pop('grouping',None) \n" + + "mon_grouping = actual.pop('mon_grouping',None) \n" + + "result = set( actual.items() ) ^ set(expected.items()) \n" + + "resultGrouping = (grouping == [3,0] ) \n" + + "resultMonGrouping = (mon_grouping == [3,0] ) \n"; + // @formatter:on + PyCode code = interp.compile(script); + interp.exec(code); + PyObject result = interp.get("result"); + assertEquals(new PySet(), result); + assertPyTrue("resultGrouping"); + assertPyTrue("resultMonGrouping"); + } + + @Test + public void setlocaleJPEncodingCurrencyFallback() { + settableInit(); + /* + * Deliberately set a Japanese locale with an ANSI US codepage lacking the ¥ \uffe5 + * character. Which is a bit weird, but shows fallback. + */ + // @formatter:off + String script = + "from _locale import setlocale, localeconv\n" + + "setlocale(_locale.LC_ALL,'ja_JP.ISO8859-1') \n" + + "result = localeconv()['currency_symbol'] \n"; + // @formatter:on + interp.exec(script); + PyObject result = interp.get("result"); + assertEquals(new PyString("JPY"), result); + } + + /** + * We use the unconventional "~h" as a byte marker, rather than say \x, to show the conversion + * happens in this unit test, when troubleshooting. + */ + private String byteStr(byte[] bytes, boolean lePadding) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + sb.append("~h"); + sb.append(Integer.toHexString(bytes[i])); + if (lePadding) { + sb.append("~h0"); + } + } + return sb.toString(); + } + + private String utf16LEByteStr(String in, boolean lePadding) { + return byteStr(in.getBytes(StandardCharsets.UTF_16LE), lePadding); + } + + private void assertDictValueEquals(PyDictionary dict, String expectedValue, String key) { + assertEquals(new PyUnicode(expectedValue), dict.__getitem__(new PyString(key))); + } + + /** + * Assert byte transcription equality for the PyString found in {@code}dict{code} using + * {@code}key{code} under encoding utf-16le + */ + private void assertDictUTF16LEEquals(PyDictionary dict, String expectedStr, String key) { + PyString value = (PyString) dict.__getitem__(new PyString(key)); + // PyString applies zero padding, we need to add it to Java String to compare + assertEquals(utf16LEByteStr(expectedStr, true), utf16LEByteStr(value.getString(), false)); + } + + @Test + public void utf16EncodingAndFallback() { + /* + * Chinese Finland is not usually found in locale databases, so this lets us create our own + * locale with unusual symbols. + */ + Locale unicodeMockLocale = new Locale.Builder().setLanguage("zh").setRegion("FI").build(); + DecimalFormat df = (DecimalFormat) DecimalFormat.getInstance(unicodeMockLocale); + DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); + // no locale uses these, it is to trigger fallbacks + dfs.setMinusSign('\u2212'); + dfs.setGroupingSeparator('\u65E0'); + dfs.setDecimalSeparator('\u70B9'); + df.setDecimalFormatSymbols(dfs); + // Fallback case + PyDictionary dict = JyLocale.localeConvForFormat(df, df, "ISO8859-1"); + assertDictValueEquals(dict, "-", "negative_sign"); + assertDictValueEquals(dict, ".", "decimal_point"); + assertDictValueEquals(dict, "", "thousands_sep"); + assertDictValueEquals(dict, "", "mon_thousands_sep"); + // Check happy path where values are compatible with the encoding + dict = JyLocale.localeConvForFormat(df, df, "utf-16le"); + assertDictUTF16LEEquals(dict, "\u2212", "negative_sign"); + assertDictUTF16LEEquals(dict, "\u70B9", "decimal_point"); + assertDictUTF16LEEquals(dict, "\u65E0", "thousands_sep"); + assertDictUTF16LEEquals(dict, "\u65E0", "mon_thousands_sep"); + } + + @Test + public void negativeSignPosition() { + // per documentation for Python locale module + Locale locale = Locale.forLanguageTag("en-US"); + DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + df.setNegativePrefix("($"); // ($123) as in en-US Java 8 + df.setNegativeSuffix(")"); + assertEquals(0, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix("-"); // -123 EUR as in es_ES Spanish + df.setNegativeSuffix("EUR"); + assertEquals(1, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix(""); // No clear example of this + df.setNegativeSuffix("SPAM-"); // that is distinguishable from 4 + // fy Western Frisian doesn't qualify (see below) so this is a synthetic one. + assertEquals(2, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix("FCFA-"); // FCFA-123 as in sg-CF Sango (CAR) + df.setNegativeSuffix(""); + assertEquals(3, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix("CHF"); // CHF123- as in German Swiss Francs + df.setNegativeSuffix("-"); // Python de_CH.ISO8859-1 + assertEquals(4, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix("¤ "); // U0164 fy Western Frisian is the only Python + df.setNegativeSuffix("-"); // example of 2, and appears identical to 4 + assertEquals(4, JyLocale.negativeSignPosition(df)); + df.setNegativePrefix(""); // 123 as in empty locales + df.setNegativeSuffix(""); + assertEquals(_locale.CHAR_MAX, JyLocale.negativeSignPosition(df)); + } + + @Test + public void positiveCurrencyPrecedesValue() { + Locale locale = Locale.forLanguageTag("en-US"); + DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + df.setPositivePrefix("$"); // $123 as in en-US Java 8 + df.setPositiveSuffix(""); + assertEquals(1, JyLocale.positiveCurrencyPrecedesValue(df)); + df.setPositivePrefix(""); // 123$ (similar to 123 CHF) + df.setPositiveSuffix(" $"); + assertEquals(0, JyLocale.positiveCurrencyPrecedesValue(df)); + } + + @Test + public void negativeCurrencyPrecedesValue() { + Locale locale = Locale.forLanguageTag("en-US"); + DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + df.setNegativePrefix("($"); // ($123) as in en-US Java 8 + df.setNegativeSuffix(")"); + assertEquals(1, JyLocale.negativeCurrencyPrecedesValue(df)); + df.setNegativePrefix(""); // 123$ (similar to 123 CHF) + df.setNegativeSuffix(" $"); + assertEquals(0, JyLocale.negativeCurrencyPrecedesValue(df)); + } + + @Test + public void positiveSeparatedBySpace() { + Locale locale = Locale.forLanguageTag("en-US"); + DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + df.setPositivePrefix("$"); // $123 as in en-US Java 8 + df.setPositiveSuffix(""); + assertEquals(0, JyLocale.positiveSeparatedBySpace(df)); + df.setPositivePrefix(""); // 123 CHF + df.setPositiveSuffix(" CHF"); + assertEquals(1, JyLocale.positiveSeparatedBySpace(df)); + } + + @Test + public void negativeSeparatedBySpace() { + Locale locale = Locale.forLanguageTag("de-DE"); + DecimalFormat df = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + // Many Java locales use U+00A0, non-breaking space, for spacing, rather than " ". + assertEquals(1, JyLocale.negativeSeparatedBySpace(df)); + df.setNegativePrefix(""); // -123 € + df.setNegativeSuffix("\u00A0" + "€"); + assertEquals(1, JyLocale.negativeSeparatedBySpace(df)); + df.setNegativePrefix(""); // 123 EUR/ + df.setNegativeSuffix(" EUR"); + assertEquals(1, JyLocale.negativeSeparatedBySpace(df)); + // Many Java locales use + df.setNegativePrefix("-$"); // -$123 + df.setNegativeSuffix(""); + assertEquals(0, JyLocale.negativeSeparatedBySpace(df)); + } + + @Test + public void extendedWhitespace() { + assertTrue(JyLocale.isExtendedWhitespace(' ')); + assertFalse(JyLocale.isExtendedWhitespace('a')); + assertTrue(JyLocale.isExtendedWhitespace('\u00A0')); + assertFalse(JyLocale.isExtendedWhitespace('€')); + } + + @Test + public void getlocale() { + settableInit(); + // @formatter:off + String script = + "from locale import normalize, setlocale, getlocale, LC_ALL, LC_NUMERIC\n" + + "norm = normalize('zh_CN') \n" + + "setlocale(LC_ALL,('zh_CN',None)) \n" + + "actual = getlocale() \n" + "expected = ('zh_CN', 'gb2312') \n"; + // @formatter:on + PyCode code = interp.compile(script); + interp.exec(code); + PyObject norm = interp.get("norm"); + assertEquals(new PyString("zh_CN.gb2312"), norm); + PyObject actual = interp.get("actual"); + PyObject expected = interp.get("expected"); + assertEquals(expected, actual); + script = "actual = getlocale(LC_NUMERIC) \n"; + interp.exec(script); + actual = interp.get("actual"); + assertEquals(expected, actual); + } + + @Test + public void setlocaleC() { + settableInit(); + // @formatter:off + String script = + "from locale import setlocale, getlocale, localeconv, LC_ALL\n" + + "setlocale(LC_ALL,'C') \n" + + "actualLocale = getlocale() \n" + + "actual = localeconv() \n" + + "expected = { " + + " 'mon_decimal_point': '', 'int_frac_digits': 127, " + + " 'p_sep_by_space': 127, 'frac_digits': 127, " + + " 'thousands_sep': '', 'n_sign_posn': 127, " + + " 'decimal_point': '.', 'int_curr_symbol': '', " + + " 'n_cs_precedes': 127, 'p_sign_posn': 127, " + + " 'mon_thousands_sep': '', 'negative_sign': '', " + + " 'currency_symbol': '', 'n_sep_by_space': 127, " + + " 'p_cs_precedes': 127, 'positive_sign': '' } \n" + + "expectedLocale = (None,None) \n" + + "grouping = actual.pop('grouping',None) \n" + + "mon_grouping = actual.pop('mon_grouping',None) \n" + + "result = set( actual.items() ) ^ set(expected.items()) \n" + + "resultGrouping = (grouping == [] ) \n" + + "resultMonGrouping = (mon_grouping == [] ) \n"; + // @formatter:on + interp.exec(script); + assertInterpEquals("expectedLocale", "actualLocale"); + PyObject result = interp.get("result"); + assertEquals(new PySet(), result); + assertPyTrue("resultGrouping"); + assertPyTrue("resultMonGrouping"); + } + + @Test + public void strCompareUS() { + settableInit(); + _locale.setlocale(_locale.LC_ALL, new PyString("en_US")); + assertEquals(-1, _locale.strcoll(new PyString("aaa"), new PyString("baa"))); + assertEquals(1, _locale.strcoll(new PyString("baa"), new PyString("aaa"))); + assertEquals(0, _locale.strcoll(new PyString("knight"), new PyString("knight"))); + } + + @Test + public void strCompareChineseMainlandInterp() { + Py.writeDebug("_localeTest", "strCompareCMI()"); + // also test exposure through locale itself here + settableInit(); + // @formatter:off + String script = "from _locale import setlocale, LC_ALL, strcoll \n" + + "setlocale(LC_ALL, 'zh_CN.UTF-8' ) \n" + + "resultSame = strcoll( u'\\u4e00', u'\\u4e00' ) \n" // yi / yi + + "resultLvsU = strcoll( '\\xe4\\xb8\\x80', u'\\u4e00' ) \n" + + "resultAscii = strcoll( 'b', 'a' ) \n" + + "resultUltU1 = strcoll( u'\\u4e00', u'\\u5f00' ) \n" // yi / kai + + "resultUltU2 = strcoll( u'\\u597d', u'\\u4e00' ) \n"; // hao / yi + // @formatter:on + interp.exec(script); + assertPyEquals(0, "resultSame"); + assertPyEquals(0, "resultLvsU"); + assertPyEquals(1, "resultAscii"); + assertPyEquals(1, "resultUltU1"); + assertPyEquals(-1, "resultUltU2"); + } + + @Test + public void strCompareC() { + Py.writeDebug("_localeTest", "strCompareC()"); + // also test exposure through locale itself here + settableInit(); + // @formatter:off + String script = + "from locale import setlocale, LC_ALL, strcoll \n" + + "setlocale(LC_ALL, 'C' ) \n" + + "result1 = strcoll( 'a', 'b' ) \n" + + "result2 = strcoll( 'b', 'a' ) \n"; + // @formatter:on + interp.exec(script); + assertPyEquals(-1, "result1"); + assertPyEquals(1, "result2"); + } + + @Test + public void strxfrm() { + Py.writeDebug("_localeTest", "strxfrm()"); + settableInit(); + // @formatter:off + String script = + "from _locale import setlocale, LC_ALL, strxfrm \n" + + "setlocale(LC_ALL, 'zh_CN.UTF-8' ) \n" + + "resultU = strxfrm( u'\\u4e00') \n" + + "resultL = strxfrm( '\\xe4\\xb8\\x80' ) \n" + + "result1 = (resultU == u'\\u4e00') \n" + + "result2 = (resultU == resultL) \n" ; + // @formatter:on + interp.exec(script); + assertPyTrue("result1"); + assertPyTrue("result2"); + } + + @Test + public void dateSymbols() { + settableInit(); + // @formatter:off + String script = + "from locale import setlocale, LC_ALL \n" + + "from datetime import datetime \n" + + "setlocale(LC_ALL, 'C' ) \n" + + "resultC = datetime(2019,04,15,15, 56, 44).strftime('%c') \n" + + "setlocale(LC_ALL, 'de_DE' ) \n" + + "resultD = datetime(1919,05,16,15, 56, 44).strftime('%A %Y') \n" ; + // @formatter:on + interp.exec(script); + assertPyEquals("Mon Apr 15 15:56:44 2019", "resultC"); + assertPyEquals("Freitag 1919", "resultD"); + } + +} diff --git a/tests/java/org/python/tests/mro/EclipseChallengeMRO.java b/tests/java/org/python/tests/mro/EclipseChallengeMRO.java new file mode 100644 index 000000000..03db73659 --- /dev/null +++ b/tests/java/org/python/tests/mro/EclipseChallengeMRO.java @@ -0,0 +1,36 @@ +// Copyright (c)2019 Jython Developers. +// Licensed to the Python Software Foundation under a Contributor Agreement. + +package org.python.tests.mro; + +/** + * A class providing interface and abstract class relationships that approximate the structure of + * org.eclipse.emf.ecore.util.DelegatingFeatureMap, in order to exercise b.j.o issue 2445. The + * complex inheritance confused PyJavaType handling of the MRO. This class is imported by + * {@code test_java_integration.JavaMROTest.test_mro_eclipse} as a test. + *

    + * An invocation at the prompt (for debugging use), and output before the fix, is:

    + * PS > dist\bin\jython -S -c"from org.python.tests.mro import EclipseChallengeMRO"
    + * Traceback (most recent call last):
    + *   File "<string>", line 1, in <module>
    + * TypeError: Supertypes that share a modified attribute have an MRO
    + * conflict[attribute=sort, supertypes=[<type 'java.util.List'>,
    + * <type 'java.util.AbstractList'>], type=EclipseChallengeMRO$Target]
    + * 
    + */ +public class EclipseChallengeMRO { + + interface Entry {} // Was FeatureMap.Entry + interface Thing {} // Was EStructuralFeature.Setting + interface EList extends java.util.List {} + interface IEList extends EList {} + interface FList extends EList {} // Was FeatureMap + interface FIEListThing extends FList, IEList, Thing {} // Was 2 FeatureMap.Internal + abstract static class AbstractEList extends java.util.AbstractList implements EList {} + abstract static class DEList extends AbstractEList {} + interface NList extends EList {} + abstract static class DNListImpl extends DEList implements NList {} + abstract static class DNIEListImpl extends DNListImpl implements IEList {} + abstract static class DNIEListThing extends DNIEListImpl implements Thing {} + public abstract static class Target extends DNIEListThing implements FIEListThing {} +} diff --git a/tests/java/org/python/tests/mro/IBMMQChallengeMRO.java b/tests/java/org/python/tests/mro/IBMMQChallengeMRO.java new file mode 100644 index 000000000..9867978f0 --- /dev/null +++ b/tests/java/org/python/tests/mro/IBMMQChallengeMRO.java @@ -0,0 +1,93 @@ +// Copyright (c)2019 Jython Developers. +// Licensed to the Python Software Foundation under a Contributor Agreement. + +package org.python.tests.mro; + +import java.io.Serializable; +import java.util.Map; + +/** + * A class providing interface and abstract class relationships that approximate the structure of + * com.ibm classes related to MQ, in order to exercise b.j.o issue 2445. The complex inheritance + * confused PyJavaType handling of the MRO. This class is imported by + * {@code test_java_integration.JavaMROTest.test_mro_ibmmq}. + *

    + * An invocation at the prompt (for debugging use), and output before the fix, is:

    + * PS > dist\bin\jython -S -c "from org.python.tests.mro import IBMMQChallengeMRO; t=m.mq.jms.MQQueue"
    + * Traceback (most recent call last):
    + *   File "<string>", line 1, in <module>
    + * TypeError: Supertypes that share a modified attribute have an MRO conflict
    + * [attribute=get,supertypes=[<type
    + * 'org.python.tests.mro.IBMMQChallengeMRO$msg$client$jms$internal$JmsPropertyContextImpl'>],
    + * type=IBMMQChallengeMRO$mq$jms$MQQueue]
    + * 
    + */ +public class IBMMQChallengeMRO { + + static class javax_jms { // represents javax.jms + + public interface Queue extends Destination {} + public interface Destination {} + } + + static class javax_naming { // represents javax.naming + + public interface Referenceable {} + } + + static class msg { // represents com.ibm.msg + + static class client { // represents com.ibm.msg.client + + static class jms { // represents com.ibm.msg.client.jms + + public interface JmsDestination extends JmsPropertyContext, javax_jms.Destination {} + public interface JmsPropertyContext + extends JmsReadablePropertyContext, Map {} + public interface JmsReadablePropertyContext extends Serializable {} + public interface JmsQueue extends JmsDestination, javax_jms.Queue {} + + static class admin { // represents com.ibm.msg.client.jms.admin + + public static abstract/* ? */ class JmsJndiDestinationImpl + extends JmsDestinationImpl + implements JmsDestination, javax_naming.Referenceable, Serializable {} + public static abstract/* ? */ class JmsDestinationImpl + extends internal.JmsPropertyContextImpl implements JmsDestination {} + } + + static class internal { // represents com.ibm.msg.client.jms.internal + + public static abstract/* ? */ class JmsPropertyContextImpl + extends JmsReadablePropertyContextImpl implements JmsPropertyContext, + provider.ProviderPropertyContextCallback {} + public static abstract class JmsReadablePropertyContextImpl + implements JmsReadablePropertyContext {} + } + } + + static class provider { // represents com.ibm.msg.client.provider + + public interface ProviderPropertyContextCallback {} + } + } + } + + static class jms { // represents com.ibm.jms + + public interface JMSDestination extends javax_jms.Destination {} + } + + public static class mq { // represents com.ibm.mq + + public static class jms { // represents com.ibm.mq.jms + + public abstract/* ? */ class MQDestination + extends msg.client.jms.admin.JmsJndiDestinationImpl implements + javax_jms.Destination, IBMMQChallengeMRO.jms.JMSDestination, Serializable {} + /** Target class in the test **/ + public abstract/* ? */ class MQQueue extends MQDestination implements javax_jms.Queue, + msg.client.jms.JmsQueue, javax_naming.Referenceable, Serializable {} + } + } +} diff --git a/tests/java/org/python/util/jythonTest.java b/tests/java/org/python/util/jythonTest.java index bdf8adba0..947d0fff5 100644 --- a/tests/java/org/python/util/jythonTest.java +++ b/tests/java/org/python/util/jythonTest.java @@ -35,7 +35,7 @@ public class jythonTest { */ @Test public void testDefaultConsole() { - jython.run(commands); + jython.main(commands); Console console = Py.getConsole(); assertEquals(JLineConsole.class, console.getClass()); } diff --git a/tests/java/org/python/util/jythonTestPlain.java b/tests/java/org/python/util/jythonTestPlain.java index 777f39d3c..beb7c13cf 100644 --- a/tests/java/org/python/util/jythonTestPlain.java +++ b/tests/java/org/python/util/jythonTestPlain.java @@ -1,6 +1,7 @@ package org.python.util; import static org.junit.Assert.*; +import static org.python.core.RegistryKey.PYTHON_CONSOLE; import org.junit.Test; import org.python.core.Console; @@ -27,7 +28,6 @@ */ public class jythonTestPlain { - private static final String PYTHON_CONSOLE = "python.console"; private static String[] commands = {"-c", "import sys; print type(sys._jy_console)"}; /** @@ -39,7 +39,7 @@ public class jythonTestPlain { public void testFallbackConsole() { System.out.println("testFallbackConsole"); System.getProperties().setProperty(PYTHON_CONSOLE, "org.python.util.InteractiveConsole"); - jython.run(commands); + jython.main(commands); Console console = Py.getConsole(); assertEquals(PlainConsole.class, console.getClass()); } @@ -55,7 +55,7 @@ public void testChangeConsole() throws Exception { PythonInterpreter interp = new PythonInterpreter(); // Now replace it Py.installConsole(new JLineConsole(null)); - jython.run(commands); + jython.main(commands); Console console = Py.getConsole(); assertEquals(JLineConsole.class, console.getClass()); interp.cleanup(); diff --git a/tests/modjy/build.xml b/tests/modjy/build.xml index 80367e036..fd2a7bb1e 100644 --- a/tests/modjy/build.xml +++ b/tests/modjy/build.xml @@ -58,6 +58,7 @@ + diff --git a/tests/modjy/java/com/xhaus/modjy/ModjyTestAppInvocation.java b/tests/modjy/java/com/xhaus/modjy/ModjyTestAppInvocation.java index 3118121eb..e19df5ef0 100644 --- a/tests/modjy/java/com/xhaus/modjy/ModjyTestAppInvocation.java +++ b/tests/modjy/java/com/xhaus/modjy/ModjyTestAppInvocation.java @@ -194,6 +194,10 @@ public void testBadAppImport() throws Exception { assertEquals("Status code != 500: ServerError, =='" + getStatus() + "'", 500, getStatus()); } + /* + * 5 tests are disabled until we can supply invocation_tests.py, missing from the code base. + * See https://bugs.jython.org/issue2794 . + * protected void callableQueryAppInvocationTestSetUp() throws Exception { baseSetUp(); setRealPath("/test_apps_dir", "test_apps_dir"); @@ -254,5 +258,6 @@ public void testCallableQueryStringParamNonExistentValue() throws Exception { String result = getOutput(); assertEquals("Status code != 500: ServerError, =='" + getStatus() + "'", 500, getStatus()); } - + * + */ }
    Stream behaviour for various object types
    Python type of object o written