Name | custom-numbers JSON |
Version |
1.3.1
JSON |
| download |
home_page | None |
Summary | Swiss-army knife for numbers of custom numeral systems. |
upload_time | 2024-03-29 20:01:53 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | MIT License Copyright (c) 2023 Evgueni Antonov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
counter
math
mathematics
number
numbers
numeral
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# custom_numbers 1.3.1
## DESCRIPTION
A Swiss-army knife for numbers of custom numeral systems.
## AUTHOR
Evgueni Antonov 2023.
## NOTE
This module was created and tested on Python 3.10.6, pip 23.1.2.
First time published in May 2023.
## INSTALLATION
```
pip3 install custom-numbers
# or
python3 -m pip install custom-numbers
```
## QUICKSTART
For details on how to use it, see the USAGE section below.
```
from custom_numbers import custom_numbers as cn
my_custom_numeral_system = cn.CustomNumeralSystem("paf")
my_number = cn.CustomNumber(my_custom_numeral_system, "a")
# Now if you type in REPL:
# help(cn)
# You will get the help for the module and the classes.
```
## USAGE
This package contains one module with few classes made to help you declare
a custom numeral system, made of custom symbols with a custom base. As
this may sound strange, in reality this is how it looks:
> NOTE: Subsystems are not supported and I do not plan to implement this
> feature.
> NOTE: This module supports only custom integer numbers. Custom
> floating point numbers are not supported and will never be.
### QUICK RECAP ON EXISTING AND WELL-KNOWN NUMERAL SYSTEMS
Let's start with something you already know - a binary number. These
are made of only **zeroes and ones** and therefore the Base is 2.
> Example: 1100101
and this actually is the title of a really cool song from the 90s.
Also **1100101** binary, converted to decimal is **101** (a hundred and one),
just like (binary) **10<sub>2</sub>** == **2<sub>10</sub>** (decimal).
Now - a hexadecimal number - these are made of the digits
**0, 1, 2, 3, 4, 5, 6, 7, 8, 9** and the letters
**A, B, C, D, E, F** and have a Base of 16.
So a hexadecimal number looks like this:
> F<sub>16</sub> == 15<sub>10</sub>,
> 10<sub>16</sub> == 16<sub>10</sub>,
> F0<sub>16</sub> == 240<sub>10</sub>
The other well-known numeral system is the octal system, consisting of
only digits from zero to seven and Base 8, but we will skip this one now.
And finally the decimal system which we all know since childhood have a
Base of 10 and is made of the digits from zero to nine.
### TUTORIAL: DECLARING A CUSTOM NUMERAL SYSTEM
Okay, so far you are familiar with the most widely used numeral systems -
the binary, the octal, the decimal and the hexadecimal.
Let's start by re-defining the binary system. So it does have a Base of 2
and we won't change that. However how about instead of using **0 and 1**
to use **P and A** instead? So **P** would be our new zero and **A** would
be our new one. Therefore as we normally would write **1100101** this now
would be written as **AAPPAPA**. Confusing, right? But so what - it is
still a binary system, we just changed the symbols.
But now how about something crazier - a numeral system with a Base of 3,
using the symbols **P, A, F** as digits, so **F** would be **2** decimal,
**P** would be **0** decimal. Therefore:
> AA<sub>3</sub> == 4<sub>10</sub>,
> AF<sub>3</sub> == 5<sub>10</sub>,
> FP<sub>3</sub> == 6<sub>10</sub>
Now let's see this in action:
```
from custom_numbers import custom_numbers as cn
sys3 = cn.CustomNumeralSystem("paf")
num3 = cn.CustomNumber(sys3, "aa")
num10 = num3.to_decimal()
print(num10) # Prints "4"
```
Best way to test if the classes work as expected is to declare numeral
systems with the symbols we all know:
```
from custom_numbers import custom_numbers as cn
sys2 = cn.CustomNumeralSystem("01")
num2 = cn.CustomNumber(sys2, "1100101")
num10 = num2.to_decimal()
print(num10) # Prints "101"
sys16 = cn.CustomNumeralSystem("0123456789abcdef")
num16 = cn.CustomNumber(sys16, "f0")
num10 = num16.to_decimal()
print(num10) # Prints "240"
```
So far so good. Now let's go totally nuts and declare a system with a
Base greather than 16 and a totally weird set of symbols for digits.
And we can actually do that and even more totally crazy stuff:
```
sysN = cn.CustomNumeralSystem("kje5nCs21Q9vW0KMqc")
```
> NOTE: The custom numbers are CASE SENSITIVE!!
> So **N != n** !!
> NOTE: There are forbidden characters, which can't be used in a numeral
> system and can't be used in a number. You could always get them as a
> string by using the **forbidden_characters** property of the
> **CustomNumeralSystem** class.
### TUTORIAL: BASIC OPERATIONS
In **CustomNumeralSystem** class for the needs of basic validation,
the equality and iequality Python operators were implemented, so you
could compare two objects.
However the comparisson would be by the list (basically the string)
of the characters representing the digits, rather than standard
Python object (reference) comparisson.
```
sys1 = cn.CustomNumeralSystem("paf")
sys2 = cn.CustomNumeralSystem("paf")
# The two objects are different, despite being initialized with
# the same value
id(sys1) == id(sys2) # False
# However the set of characters (the digits) is the same, the
# base is the same, so I accept they are the same numeral systems
sys1 == sys2 # True
# And you could also test for inequality
sys1 = cn.CustomNumeralSystem("paf")
sys2 = cn.CustomNumeralSystem("paz")
sys1 != sys2 # True
```
Signed custom numbers are supported as well.
```
sysN = cn.CustomNumeralSystem("paf")
numN1 = cn.CustomNumber(sysN, "-a") # A negative number
numN2 = cn.CustomNumber(sysN, "a") # A positive number
numN3 = cn.CustomNumber(sysN, "+a") # A positive number
```
Basic math operations are supported trough standard Python operators.
```
sysN = cn.CustomNumeralSystem("paf")
numN1 = cn.CustomNumber(sysN, "-a")
numN2 = cn.CustomNumber(sysN, "a")
numN3 = cn.CustomNumber(sysN, "+a")
# Comparisson
numN1 == numN2
numN1 != numN2
numN1 > numN2
numN1 < numN2
numN1 >= numN2
numN1 <= numN2
# Basic mathematical operations
numN1 + numN2 # Addition
numN1 += numN2 # Augmented addition
numN1 - numN2 # Subtraction
numN1 -= numN2 # Augmented subtraction
numN1 // numN2 # Floor division
numN1 / numN2 # NOTE: This will perform floor division as well!
# as floating point numbers are not supported by this class and will
# never be.
numN1 * numN2 # Multiplication
numN1 ** numN2 # Power
numN1 % numN2 # Modulo division
abs(numN) # Absolute value
```
Using the iterator:
```
sysN = cn.CustomNumeralSystem("paf")
it = cn.GearIterator(sysN, 0, 2)
next(it) # "p" # "p" assumes to be the analog of the zero
next(it) # "a"
next(it) # "f"
next(it) # "ap"
next(it) # "aa"
# and so on. You get the idea.
# The iterator could also be initialized with an init_value which is
# de-facto a custom number from the chosen CustomNumeralSystem,
# but for convenience I left the number to be a string, as you may
# wish or not to initialize at all:
it = cn.GearIterator(sysN, 0, 2, "af")
```
> NOTE: If initialized, the iterator will strip any leading "zeroes"
> (so to speak) from the given init_value.
### class CustomNumeralSystem
Defines and declares a custom numeral system.
```
CustomNumeralSystem(digits: str)
Args:
digits: The symbols to be used as digits. The string length defines
the numeral system base.
```
PROPERTIES:
```
forbidden_characters -> str
base -> int
```
METHODS:
```
valid_number(number: str) -> bool
Tests if the given "number" is valid for the current numeral system.
Should not contain forbidden characters.
Should contain only characters defined in the numeral system.
```
### class CustomNumber
Defines and declares a number from a custom numeral system.
```
CustomNumber(numeral_system: CustomNumeralSystem, value: str)
Args:
numeral_system: A previously defined custom numeral system.
value: The value (the number itself).
```
PROPERTIES:
```
init_value -> str
Returns the initial value the class was initialized with.
```
METHODS:
```
digit_to_int(digit: str) -> int
Converts the given digit from the custom numeral system to a
decimal integer.
to_decimal() -> int
Converts the current number value to a decimal integer.
```
### class GearIterator
Iterates over the numbers of a custom numeral system eiter starting at
the very first number (the zero-equivalent) or starting from a given
init_value.
Briefly simulates old gear counters, like the old cars odometer.
```
GearIterator(numeral_system: CustomNumeralSystem, min_length: int = 0, max_length: int = 0, init_value: str = "")
Args:
numeral_system: Custom numeral system. Mind the order of symbols!
min_length: Minimum length, default is zero.
max_length: Maximum length, default is zero - means no limit.
init_value: Value to initialize with.
```
PROPERTIES:
```
combinations -> int
Returns the number of possible combinations (iterations).
```
> The class implements the Python context management protocol.
Raw data
{
"_id": null,
"home_page": null,
"name": "custom-numbers",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "counter, math, mathematics, number, numbers, numeral",
"author": null,
"author_email": "Evgueni Antonov <Evgueni.Antonov@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/26/d0/a778318fff95fb6e31e09fe90813cbdff6e862553e3b61620fd771ae9248/custom_numbers-1.3.1.tar.gz",
"platform": null,
"description": "# custom_numbers 1.3.1\n\n## DESCRIPTION\n\nA Swiss-army knife for numbers of custom numeral systems.\n\n## AUTHOR\n\nEvgueni Antonov 2023.\n\n## NOTE\n\nThis module was created and tested on Python 3.10.6, pip 23.1.2.\n\nFirst time published in May 2023.\n\n## INSTALLATION\n\n```\npip3 install custom-numbers\n# or\npython3 -m pip install custom-numbers\n```\n\n## QUICKSTART\n\nFor details on how to use it, see the USAGE section below.\n\n```\nfrom custom_numbers import custom_numbers as cn\n\nmy_custom_numeral_system = cn.CustomNumeralSystem(\"paf\")\nmy_number = cn.CustomNumber(my_custom_numeral_system, \"a\")\n\n# Now if you type in REPL:\n# help(cn)\n# You will get the help for the module and the classes.\n```\n\n## USAGE\n\nThis package contains one module with few classes made to help you declare\na custom numeral system, made of custom symbols with a custom base. As\nthis may sound strange, in reality this is how it looks:\n\n> NOTE: Subsystems are not supported and I do not plan to implement this\n> feature.\n\n> NOTE: This module supports only custom integer numbers. Custom\n> floating point numbers are not supported and will never be.\n\n### QUICK RECAP ON EXISTING AND WELL-KNOWN NUMERAL SYSTEMS\n\nLet's start with something you already know - a binary number. These\nare made of only **zeroes and ones** and therefore the Base is 2.\n\n> Example: 1100101\n\nand this actually is the title of a really cool song from the 90s.\nAlso **1100101** binary, converted to decimal is **101** (a hundred and one),\njust like (binary) **10<sub>2</sub>** == **2<sub>10</sub>** (decimal).\n\nNow - a hexadecimal number - these are made of the digits\n**0, 1, 2, 3, 4, 5, 6, 7, 8, 9** and the letters\n**A, B, C, D, E, F** and have a Base of 16.\n\nSo a hexadecimal number looks like this:\n\n> F<sub>16</sub> == 15<sub>10</sub>, \n> 10<sub>16</sub> == 16<sub>10</sub>, \n> F0<sub>16</sub> == 240<sub>10</sub>\n\nThe other well-known numeral system is the octal system, consisting of\nonly digits from zero to seven and Base 8, but we will skip this one now.\n\nAnd finally the decimal system which we all know since childhood have a\nBase of 10 and is made of the digits from zero to nine.\n\n### TUTORIAL: DECLARING A CUSTOM NUMERAL SYSTEM\n\nOkay, so far you are familiar with the most widely used numeral systems -\nthe binary, the octal, the decimal and the hexadecimal.\n\nLet's start by re-defining the binary system. So it does have a Base of 2\nand we won't change that. However how about instead of using **0 and 1**\nto use **P and A** instead? So **P** would be our new zero and **A** would\nbe our new one. Therefore as we normally would write **1100101** this now\nwould be written as **AAPPAPA**. Confusing, right? But so what - it is\nstill a binary system, we just changed the symbols.\n\nBut now how about something crazier - a numeral system with a Base of 3,\nusing the symbols **P, A, F** as digits, so **F** would be **2** decimal,\n**P** would be **0** decimal. Therefore:\n\n> AA<sub>3</sub> == 4<sub>10</sub>, \n> AF<sub>3</sub> == 5<sub>10</sub>, \n> FP<sub>3</sub> == 6<sub>10</sub>\n\nNow let's see this in action:\n\n```\nfrom custom_numbers import custom_numbers as cn\n\nsys3 = cn.CustomNumeralSystem(\"paf\")\nnum3 = cn.CustomNumber(sys3, \"aa\")\nnum10 = num3.to_decimal()\nprint(num10) # Prints \"4\"\n```\n\nBest way to test if the classes work as expected is to declare numeral\nsystems with the symbols we all know:\n\n```\nfrom custom_numbers import custom_numbers as cn\n\nsys2 = cn.CustomNumeralSystem(\"01\")\nnum2 = cn.CustomNumber(sys2, \"1100101\")\nnum10 = num2.to_decimal()\nprint(num10) # Prints \"101\"\n\nsys16 = cn.CustomNumeralSystem(\"0123456789abcdef\")\nnum16 = cn.CustomNumber(sys16, \"f0\")\nnum10 = num16.to_decimal()\nprint(num10) # Prints \"240\"\n```\n\nSo far so good. Now let's go totally nuts and declare a system with a\nBase greather than 16 and a totally weird set of symbols for digits.\nAnd we can actually do that and even more totally crazy stuff:\n\n```\nsysN = cn.CustomNumeralSystem(\"kje5nCs21Q9vW0KMqc\")\n```\n\n> NOTE: The custom numbers are CASE SENSITIVE!!\n> So **N != n** !!\n\n> NOTE: There are forbidden characters, which can't be used in a numeral\n> system and can't be used in a number. You could always get them as a\n> string by using the **forbidden_characters** property of the \n> **CustomNumeralSystem** class.\n\n### TUTORIAL: BASIC OPERATIONS\n\nIn **CustomNumeralSystem** class for the needs of basic validation, \nthe equality and iequality Python operators were implemented, so you \ncould compare two objects.\n\nHowever the comparisson would be by the list (basically the string)\nof the characters representing the digits, rather than standard\nPython object (reference) comparisson.\n\n```\nsys1 = cn.CustomNumeralSystem(\"paf\")\nsys2 = cn.CustomNumeralSystem(\"paf\")\n\n# The two objects are different, despite being initialized with\n# the same value\nid(sys1) == id(sys2) # False\n\n# However the set of characters (the digits) is the same, the \n# base is the same, so I accept they are the same numeral systems\nsys1 == sys2 # True\n\n# And you could also test for inequality\nsys1 = cn.CustomNumeralSystem(\"paf\")\nsys2 = cn.CustomNumeralSystem(\"paz\")\nsys1 != sys2 # True\n```\n\nSigned custom numbers are supported as well.\n\n```\nsysN = cn.CustomNumeralSystem(\"paf\")\nnumN1 = cn.CustomNumber(sysN, \"-a\") # A negative number\nnumN2 = cn.CustomNumber(sysN, \"a\") # A positive number\nnumN3 = cn.CustomNumber(sysN, \"+a\") # A positive number\n```\n\nBasic math operations are supported trough standard Python operators.\n\n```\nsysN = cn.CustomNumeralSystem(\"paf\")\nnumN1 = cn.CustomNumber(sysN, \"-a\")\nnumN2 = cn.CustomNumber(sysN, \"a\")\nnumN3 = cn.CustomNumber(sysN, \"+a\")\n\n# Comparisson\nnumN1 == numN2\nnumN1 != numN2\nnumN1 > numN2\nnumN1 < numN2\nnumN1 >= numN2\nnumN1 <= numN2\n\n# Basic mathematical operations\nnumN1 + numN2 # Addition\nnumN1 += numN2 # Augmented addition\nnumN1 - numN2 # Subtraction\nnumN1 -= numN2 # Augmented subtraction\nnumN1 // numN2 # Floor division\nnumN1 / numN2 # NOTE: This will perform floor division as well!\n# as floating point numbers are not supported by this class and will\n# never be.\nnumN1 * numN2 # Multiplication\nnumN1 ** numN2 # Power\nnumN1 % numN2 # Modulo division\nabs(numN) # Absolute value\n```\n\nUsing the iterator:\n\n```\nsysN = cn.CustomNumeralSystem(\"paf\")\nit = cn.GearIterator(sysN, 0, 2)\nnext(it) # \"p\" # \"p\" assumes to be the analog of the zero\nnext(it) # \"a\"\nnext(it) # \"f\"\nnext(it) # \"ap\"\nnext(it) # \"aa\"\n# and so on. You get the idea.\n\n# The iterator could also be initialized with an init_value which is\n# de-facto a custom number from the chosen CustomNumeralSystem,\n# but for convenience I left the number to be a string, as you may\n# wish or not to initialize at all:\nit = cn.GearIterator(sysN, 0, 2, \"af\")\n```\n\n> NOTE: If initialized, the iterator will strip any leading \"zeroes\"\n> (so to speak) from the given init_value.\n\n### class CustomNumeralSystem\n\nDefines and declares a custom numeral system.\n\n```\nCustomNumeralSystem(digits: str)\n\nArgs:\n digits: The symbols to be used as digits. The string length defines\n the numeral system base.\n```\n\nPROPERTIES:\n\n```\nforbidden_characters -> str\nbase -> int\n```\n\nMETHODS:\n\n```\nvalid_number(number: str) -> bool\n Tests if the given \"number\" is valid for the current numeral system.\n Should not contain forbidden characters.\n Should contain only characters defined in the numeral system.\n```\n\n### class CustomNumber\n\nDefines and declares a number from a custom numeral system.\n\n```\nCustomNumber(numeral_system: CustomNumeralSystem, value: str)\n\nArgs:\n numeral_system: A previously defined custom numeral system.\n value: The value (the number itself).\n```\n\nPROPERTIES:\n\n```\ninit_value -> str\n Returns the initial value the class was initialized with.\n```\n\nMETHODS:\n\n```\ndigit_to_int(digit: str) -> int\n Converts the given digit from the custom numeral system to a\n decimal integer.\n\nto_decimal() -> int\n Converts the current number value to a decimal integer.\n```\n\n### class GearIterator\n\nIterates over the numbers of a custom numeral system eiter starting at\nthe very first number (the zero-equivalent) or starting from a given\ninit_value.\n\nBriefly simulates old gear counters, like the old cars odometer.\n\n```\nGearIterator(numeral_system: CustomNumeralSystem, min_length: int = 0, max_length: int = 0, init_value: str = \"\")\n\nArgs:\n numeral_system: Custom numeral system. Mind the order of symbols!\n min_length: Minimum length, default is zero.\n max_length: Maximum length, default is zero - means no limit.\n init_value: Value to initialize with.\n```\n\nPROPERTIES:\n\n```\ncombinations -> int\n Returns the number of possible combinations (iterations).\n```\n\n> The class implements the Python context management protocol.\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2023 Evgueni Antonov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.",
"summary": "Swiss-army knife for numbers of custom numeral systems.",
"version": "1.3.1",
"project_urls": {
"Bug Tracker": "https://github.com/StrayFeral/custom_numbers/issues",
"Homepage": "https://github.com/StrayFeral/custom_numbers"
},
"split_keywords": [
"counter",
" math",
" mathematics",
" number",
" numbers",
" numeral"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "b46b55ed613f9863aea3f46473a396806e742f059523cfc4828f5c68d86944db",
"md5": "950f03a24a00d54151f0e748867bb919",
"sha256": "fe745bf2d5225b47609c63382e5b51525973e699aee19edce9b189a82cea6c0b"
},
"downloads": -1,
"filename": "custom_numbers-1.3.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "950f03a24a00d54151f0e748867bb919",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 10814,
"upload_time": "2024-03-29T20:01:51",
"upload_time_iso_8601": "2024-03-29T20:01:51.036660Z",
"url": "https://files.pythonhosted.org/packages/b4/6b/55ed613f9863aea3f46473a396806e742f059523cfc4828f5c68d86944db/custom_numbers-1.3.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "26d0a778318fff95fb6e31e09fe90813cbdff6e862553e3b61620fd771ae9248",
"md5": "ed409a5469de228664aa2fe2481cc3e5",
"sha256": "102dfa95108357c0a1de3b2b1b208372e6782e7ee4908a0f5c8d215bce0d504b"
},
"downloads": -1,
"filename": "custom_numbers-1.3.1.tar.gz",
"has_sig": false,
"md5_digest": "ed409a5469de228664aa2fe2481cc3e5",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 14725,
"upload_time": "2024-03-29T20:01:53",
"upload_time_iso_8601": "2024-03-29T20:01:53.090889Z",
"url": "https://files.pythonhosted.org/packages/26/d0/a778318fff95fb6e31e09fe90813cbdff6e862553e3b61620fd771ae9248/custom_numbers-1.3.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-29 20:01:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "StrayFeral",
"github_project": "custom_numbers",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [],
"lcname": "custom-numbers"
}