Lint code
This commit is contained in:
parent
86a8bf481d
commit
8a62293a47
|
@ -27,11 +27,12 @@ except ImportError:
|
||||||
|
|
||||||
import boxes.generators
|
import boxes.generators
|
||||||
|
|
||||||
#__version__ = get_distribution('boxes').version
|
|
||||||
|
# __version__ = get_distribution('boxes').version
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
#version = 'boxes.py v{}'.format(__version__)
|
# version = 'boxes.py v{}'.format(__version__)
|
||||||
|
|
||||||
if len(sys.argv) > 1 and sys.argv[1].startswith("--id="):
|
if len(sys.argv) > 1 and sys.argv[1].startswith("--id="):
|
||||||
del sys.argv[1]
|
del sys.argv[1]
|
||||||
|
@ -45,9 +46,11 @@ def main():
|
||||||
name = name[12:]
|
name = name[12:]
|
||||||
run_generator(name, sys.argv[2:])
|
run_generator(name, sys.argv[2:])
|
||||||
|
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
print(__doc__)
|
print(__doc__)
|
||||||
|
|
||||||
|
|
||||||
def list_grouped_generators():
|
def list_grouped_generators():
|
||||||
print('Available generators:')
|
print('Available generators:')
|
||||||
for group in generator_groups():
|
for group in generator_groups():
|
||||||
|
@ -59,12 +62,14 @@ def list_grouped_generators():
|
||||||
for box in group.generators:
|
for box in group.generators:
|
||||||
print(' * {} - {}'.format(box.__name__, box.__doc__ or ''))
|
print(' * {} - {}'.format(box.__name__, box.__doc__ or ''))
|
||||||
|
|
||||||
|
|
||||||
def get_translation():
|
def get_translation():
|
||||||
try:
|
try:
|
||||||
return gettext.translation('boxes.py', localedir='locale')
|
return gettext.translation('boxes.py', localedir='locale')
|
||||||
except OSError:
|
except OSError:
|
||||||
return gettext.translation('boxes.py', fallback=True)
|
return gettext.translation('boxes.py', fallback=True)
|
||||||
|
|
||||||
|
|
||||||
def run_generator(name, args):
|
def run_generator(name, args):
|
||||||
generators = generators_by_name()
|
generators = generators_by_name()
|
||||||
lower_name = name.lower()
|
lower_name = name.lower()
|
||||||
|
|
|
@ -25,9 +25,10 @@ except ImportError:
|
||||||
sys.path.append(os.path.dirname(__file__) + "/..")
|
sys.path.append(os.path.dirname(__file__) + "/..")
|
||||||
import boxes.generators
|
import boxes.generators
|
||||||
|
|
||||||
|
|
||||||
class Boxes2INX:
|
class Boxes2INX:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.boxes = {b.__name__ : b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
|
self.boxes = {b.__name__: b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
|
||||||
self.groups = boxes.generators.ui_groups
|
self.groups = boxes.generators.ui_groups
|
||||||
self.groups_by_name = boxes.generators.ui_groups_by_name
|
self.groups_by_name = boxes.generators.ui_groups_by_name
|
||||||
|
|
||||||
|
@ -37,44 +38,44 @@ class Boxes2INX:
|
||||||
|
|
||||||
def arg2inx(self, a, prefix):
|
def arg2inx(self, a, prefix):
|
||||||
name = a.option_strings[0].replace("-", "")
|
name = a.option_strings[0].replace("-", "")
|
||||||
|
|
||||||
if isinstance(a, argparse._HelpAction):
|
if isinstance(a, argparse._HelpAction):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
viewname = name
|
viewname = name
|
||||||
if prefix and name.startswith(prefix + '_'):
|
if prefix and name.startswith(prefix + '_'):
|
||||||
viewname = name[len(prefix)+1:]
|
viewname = name[len(prefix) + 1:]
|
||||||
|
|
||||||
if (isinstance(a, argparse._StoreAction) and hasattr(a.type, "inx")):
|
if (isinstance(a, argparse._StoreAction) and hasattr(a.type, "inx")):
|
||||||
return a.type.inx(name, viewname, a) #see boxes.__init__.py
|
return a.type.inx(name, viewname, a) # see boxes.__init__.py
|
||||||
elif a.dest == "layout":
|
elif a.dest == "layout":
|
||||||
return ""
|
return ""
|
||||||
val = a.default.split("\n")
|
val = a.default.split("\n")
|
||||||
input = """<textarea name="%s" cols="%s" rows="%s">%s</textarea>""" % \
|
input = """<textarea name="%s" cols="%s" rows="%s">%s</textarea>""" % \
|
||||||
(name, max(len(l) for l in val)+10, len(val)+1, a.default)
|
(name, max(len(l) for l in val) + 10, len(val) + 1, a.default)
|
||||||
elif a.choices:
|
elif a.choices:
|
||||||
uniqueChoices = []
|
uniqueChoices = []
|
||||||
for e in a.choices:
|
for e in a.choices:
|
||||||
if e not in uniqueChoices:
|
if e not in uniqueChoices:
|
||||||
uniqueChoices.append(e)
|
uniqueChoices.append(e)
|
||||||
return (''' <param name="%s" type="optiongroup" appearance="combo" gui-text="%s" gui-description=%s>\n'''
|
return (''' <param name="%s" type="optiongroup" appearance="combo" gui-text="%s" gui-description=%s>\n'''
|
||||||
% (name, viewname, quoteattr(a.help or viewname)) +
|
% (name, viewname, quoteattr(a.help or viewname)) +
|
||||||
"".join(' <option value="%s">%s</option>\n' % (e, e) for e in uniqueChoices) + ' </param>\n')
|
"".join(' <option value="%s">%s</option>\n' % (e, e) for e in uniqueChoices) + ' </param>\n')
|
||||||
else:
|
else:
|
||||||
default = a.default
|
default = a.default
|
||||||
if isinstance(a.type, boxes.BoolArg):
|
if isinstance(a.type, boxes.BoolArg):
|
||||||
t = '"bool"'
|
t = '"bool"'
|
||||||
default = str(a.default).lower()
|
default = str(a.default).lower()
|
||||||
|
|
||||||
elif a.type is boxes.argparseSections:
|
elif a.type is boxes.argparseSections:
|
||||||
t = '"string"'
|
t = '"string"'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
t = { int : '"int"',
|
t = {int: '"int"',
|
||||||
float : '"float" precision="2"',
|
float: '"float" precision="2"',
|
||||||
str : '"string"',
|
str: '"string"',
|
||||||
}.get(a.type, '"string"')
|
}.get(a.type, '"string"')
|
||||||
|
|
||||||
if t == '"int"' or t == '"float" precision="2"':
|
if t == '"int"' or t == '"float" precision="2"':
|
||||||
return ''' <param name="%s" type=%s max="9999" gui-text="%s" gui-description=%s>%s</param>\n''' % (name, t, viewname, quoteattr(a.help or viewname), default)
|
return ''' <param name="%s" type=%s max="9999" gui-text="%s" gui-description=%s>%s</param>\n''' % (name, t, viewname, quoteattr(a.help or viewname), default)
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ class Boxes2INX:
|
||||||
return ''' <param name="%s" type=%s gui-text="%s" gui-description=%s>%s</param>\n''' % (name, t, viewname, quoteattr(a.help or viewname), default)
|
return ''' <param name="%s" type=%s gui-text="%s" gui-description=%s>%s</param>\n''' % (name, t, viewname, quoteattr(a.help or viewname), default)
|
||||||
|
|
||||||
def generator2inx(self, name, box):
|
def generator2inx(self, name, box):
|
||||||
result = [ """<?xml version="1.0" encoding="UTF-8"?>
|
result = ["""<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
|
||||||
<name>%s</name>
|
<name>%s</name>
|
||||||
<id>info.festi.boxes.py.%s</id>
|
<id>info.festi.boxes.py.%s</id>
|
||||||
|
@ -97,12 +98,12 @@ class Boxes2INX:
|
||||||
if title.startswith("Settings for "):
|
if title.startswith("Settings for "):
|
||||||
title = title[len("Settings for "):]
|
title = title[len("Settings for "):]
|
||||||
if title.endswith(" Settings"):
|
if title.endswith(" Settings"):
|
||||||
title = title[:-len(" Settings")]
|
title = title[:-len(" Settings")]
|
||||||
|
|
||||||
pageParams = []
|
pageParams = []
|
||||||
for a in group._group_actions:
|
for a in group._group_actions:
|
||||||
if a.dest in ("input", "output", "format"):
|
if a.dest in ("input", "output", "format"):
|
||||||
continue
|
continue
|
||||||
if self.arg2inx(a, prefix) != "":
|
if self.arg2inx(a, prefix) != "":
|
||||||
pageParams.append(self.arg2inx(a, prefix))
|
pageParams.append(self.arg2inx(a, prefix))
|
||||||
if len(pageParams) > 0:
|
if len(pageParams) > 0:
|
||||||
|
@ -111,7 +112,7 @@ class Boxes2INX:
|
||||||
""" % (groupid, title))
|
""" % (groupid, title))
|
||||||
result.extend(pageParams)
|
result.extend(pageParams)
|
||||||
result.append(" </page>")
|
result.append(" </page>")
|
||||||
|
|
||||||
groupid += 1
|
groupid += 1
|
||||||
result.append("""
|
result.append("""
|
||||||
<page name="tab_%s" gui-text="Example">
|
<page name="tab_%s" gui-text="Example">
|
||||||
|
@ -145,7 +146,8 @@ class Boxes2INX:
|
||||||
continue
|
continue
|
||||||
self.writeINX(name, box, path)
|
self.writeINX(name, box, path)
|
||||||
|
|
||||||
if __name__=="__main__":
|
|
||||||
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Usage: boxes2inkscape TARGETPATH")
|
print("Usage: boxes2inkscape TARGETPATH")
|
||||||
b = Boxes2INX()
|
b = Boxes2INX()
|
||||||
|
|
|
@ -27,13 +27,14 @@ except ImportError:
|
||||||
import boxes.generators
|
import boxes.generators
|
||||||
from boxes import edges, lids
|
from boxes import edges, lids
|
||||||
|
|
||||||
|
|
||||||
class DefaultParams(boxes.Boxes):
|
class DefaultParams(boxes.Boxes):
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
boxes.Boxes.__init__(self)
|
boxes.Boxes.__init__(self)
|
||||||
self.buildArgParser("x", "y", "h", "hi", "sx", "sy", "sh",
|
self.buildArgParser("x", "y", "h", "hi", "sx", "sy", "sh",
|
||||||
"bottom_edge", "top_edge", "outside", "nema_mount")
|
"bottom_edge", "top_edge", "outside", "nema_mount")
|
||||||
self.addSettingsArgs(edges.FingerJointSettings, finger=1.0,space=1.0)
|
self.addSettingsArgs(edges.FingerJointSettings, finger=1.0, space=1.0)
|
||||||
self.addSettingsArgs(edges.StackableSettings)
|
self.addSettingsArgs(edges.StackableSettings)
|
||||||
self.addSettingsArgs(edges.HingeSettings)
|
self.addSettingsArgs(edges.HingeSettings)
|
||||||
self.addSettingsArgs(edges.SlideOnLidSettings)
|
self.addSettingsArgs(edges.SlideOnLidSettings)
|
||||||
|
@ -41,11 +42,12 @@ class DefaultParams(boxes.Boxes):
|
||||||
self.addSettingsArgs(edges.FlexSettings)
|
self.addSettingsArgs(edges.FlexSettings)
|
||||||
self.addSettingsArgs(lids.LidSettings)
|
self.addSettingsArgs(lids.LidSettings)
|
||||||
|
|
||||||
|
|
||||||
class Boxes2pot:
|
class Boxes2pot:
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.messages: list[Any] = []
|
self.messages: list[Any] = []
|
||||||
self.message_set: set[Any] = set()
|
self.message_set: set[Any] = set()
|
||||||
self.boxes = {b.__name__ : b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
|
self.boxes = {b.__name__: b() for b in boxes.generators.getAllBoxGenerators().values() if b.webinterface}
|
||||||
self.groups = boxes.generators.ui_groups
|
self.groups = boxes.generators.ui_groups
|
||||||
self.groups_by_name = boxes.generators.ui_groups_by_name
|
self.groups_by_name = boxes.generators.ui_groups_by_name
|
||||||
self._readEdgeDescriptions()
|
self._readEdgeDescriptions()
|
||||||
|
@ -79,7 +81,7 @@ class Boxes2pot:
|
||||||
prefix = getattr(group, "prefix", "")
|
prefix = getattr(group, "prefix", "")
|
||||||
name = a.option_strings[0].replace("-", "")
|
name = a.option_strings[0].replace("-", "")
|
||||||
if prefix and name.startswith(prefix + '_'):
|
if prefix and name.startswith(prefix + '_'):
|
||||||
name = name[len(prefix)+1:]
|
name = name[len(prefix) + 1:]
|
||||||
self.add(name, "parameter name for " + prefix, location)
|
self.add(name, "parameter name for " + prefix, location)
|
||||||
else:
|
else:
|
||||||
self.add(name, "parameter name", location)
|
self.add(name, "parameter name", location)
|
||||||
|
@ -103,7 +105,7 @@ class Boxes2pot:
|
||||||
if box.__doc__:
|
if box.__doc__:
|
||||||
self.add(box.__doc__, "description of " + name, location)
|
self.add(box.__doc__, "description of " + name, location)
|
||||||
if box.description:
|
if box.description:
|
||||||
self.add(box.description, "long description of "+ name + " in markdown", location)
|
self.add(box.description, "long description of " + name + " in markdown", location)
|
||||||
self.addBoxParams(name, box, location)
|
self.addBoxParams(name, box, location)
|
||||||
|
|
||||||
def writePOT(self, fn):
|
def writePOT(self, fn):
|
||||||
|
@ -120,7 +122,7 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
""")
|
""")
|
||||||
|
|
||||||
for msg, comment, reference in self.messages:
|
for msg, comment, reference in self.messages:
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
if comment:
|
if comment:
|
||||||
|
@ -128,14 +130,15 @@ msgstr ""
|
||||||
if reference:
|
if reference:
|
||||||
f.write("#: %s\n" % reference)
|
f.write("#: %s\n" % reference)
|
||||||
msg = msg.split("\n")
|
msg = msg.split("\n")
|
||||||
for i in range(len(msg)-1):
|
for i in range(len(msg) - 1):
|
||||||
msg[i] += "\\n"
|
msg[i] += "\\n"
|
||||||
f.write('msgid ')
|
f.write('msgid ')
|
||||||
for m in msg:
|
for m in msg:
|
||||||
f.write(' "%s"\n' % m.replace('"', '\\"'))
|
f.write(' "%s"\n' % m.replace('"', '\\"'))
|
||||||
f.write('msgstr ""\n')
|
f.write('msgstr ""\n')
|
||||||
|
|
||||||
if __name__=="__main__":
|
|
||||||
|
if __name__ == "__main__":
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Usage: boxes2pot TARGETPATH")
|
print("Usage: boxes2pot TARGETPATH")
|
||||||
b = Boxes2pot()
|
b = Boxes2pot()
|
||||||
|
|
|
@ -19,39 +19,40 @@ from lxml import etree
|
||||||
import tempfile
|
import tempfile
|
||||||
from shlex import quote
|
from shlex import quote
|
||||||
|
|
||||||
|
|
||||||
class boxesPyWrapper(inkex.GenerateExtension):
|
class boxesPyWrapper(inkex.GenerateExtension):
|
||||||
|
|
||||||
def add_arguments(self, pars):
|
def add_arguments(self, pars):
|
||||||
args = sys.argv[1:]
|
args = sys.argv[1:]
|
||||||
for arg in args:
|
for arg in args:
|
||||||
key=arg.split("=")[0]
|
key = arg.split("=")[0]
|
||||||
if key == "--id":
|
if key == "--id":
|
||||||
continue
|
continue
|
||||||
if len(arg.split("=")) == 2:
|
if len(arg.split("=")) == 2:
|
||||||
value=arg.split("=")[1]
|
value = arg.split("=")[1]
|
||||||
pars.add_argument(key, default=key)
|
pars.add_argument(key, default=key)
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
f, box_file = tempfile.mkstemp(".svg", "boxes.py-inkscape")
|
f, box_file = tempfile.mkstemp(".svg", "boxes.py-inkscape")
|
||||||
|
|
||||||
cmd = "boxes" #boxes.exe in this local dir (or if present in %PATH%), or boxes from $PATH in linux
|
cmd = "boxes" # boxes.exe in this local dir (or if present in %PATH%), or boxes from $PATH in linux
|
||||||
for arg in vars(self.options):
|
for arg in vars(self.options):
|
||||||
if arg in (
|
if arg in (
|
||||||
"output", "id", "ids", "selected_nodes",
|
"output", "id", "ids", "selected_nodes",
|
||||||
"input_file", "tab"):
|
"input_file", "tab"):
|
||||||
continue
|
continue
|
||||||
#fix behaviour of "original" arg which does not correctly gets
|
# fix behaviour of "original" arg which does not correctly gets
|
||||||
# interpreted if set to false
|
# interpreted if set to false
|
||||||
if arg == "original" and str(getattr(self.options, arg)) == "false":
|
if arg == "original" and str(getattr(self.options, arg)) == "false":
|
||||||
continue
|
continue
|
||||||
cmd += f" --{arg} {quote(str(getattr(self.options, arg)))}"
|
cmd += f" --{arg} {quote(str(getattr(self.options, arg)))}"
|
||||||
cmd += f" --output {box_file} {box_file}" #we need to add box_file string twice in a row. Otherwise program executable throws an error
|
cmd += f" --output {box_file} {box_file}" # we need to add box_file string twice in a row. Otherwise program executable throws an error
|
||||||
cmd = cmd.replace("boxes --generator", "boxes")
|
cmd = cmd.replace("boxes --generator", "boxes")
|
||||||
|
|
||||||
# run boxes with the parameters provided
|
# run boxes with the parameters provided
|
||||||
with os.popen(cmd, "r") as boxes:
|
with os.popen(cmd, "r") as boxes:
|
||||||
result = boxes.read()
|
result = boxes.read()
|
||||||
|
|
||||||
# check output existence
|
# check output existence
|
||||||
try:
|
try:
|
||||||
stream = open(box_file, 'r')
|
stream = open(box_file, 'r')
|
||||||
|
@ -59,18 +60,19 @@ class boxesPyWrapper(inkex.GenerateExtension):
|
||||||
inkex.utils.debug("There was no " + box_file + " output generated. Cannot continue. Command was:")
|
inkex.utils.debug("There was no " + box_file + " output generated. Cannot continue. Command was:")
|
||||||
inkex.utils.debug(str(cmd))
|
inkex.utils.debug(str(cmd))
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
# write the generated SVG into Inkscape's canvas
|
# write the generated SVG into Inkscape's canvas
|
||||||
p = etree.XMLParser(huge_tree=True)
|
p = etree.XMLParser(huge_tree=True)
|
||||||
doc = etree.parse(stream, parser=etree.XMLParser(huge_tree=True))
|
doc = etree.parse(stream, parser=etree.XMLParser(huge_tree=True))
|
||||||
stream.close()
|
stream.close()
|
||||||
if os.path.exists(box_file):
|
if os.path.exists(box_file):
|
||||||
os.remove(box_file) #remove previously generated box file at the end too
|
os.remove(box_file) # remove previously generated box file at the end too
|
||||||
|
|
||||||
group = inkex.Group(id="boxes.py")
|
group = inkex.Group(id="boxes.py")
|
||||||
for element in doc.getroot():
|
for element in doc.getroot():
|
||||||
group.append(element)
|
group.append(element)
|
||||||
return group
|
return group
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
boxesPyWrapper().run()
|
boxesPyWrapper().run()
|
||||||
|
|
|
@ -81,6 +81,7 @@ class FileChecker(threading.Thread):
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
self._stopped = True
|
self._stopped = True
|
||||||
|
|
||||||
|
|
||||||
def filter_url(url, non_default_args):
|
def filter_url(url, non_default_args):
|
||||||
if len(url) == 0:
|
if len(url) == 0:
|
||||||
return ''
|
return ''
|
||||||
|
@ -102,6 +103,7 @@ def filter_url(url, non_default_args):
|
||||||
else:
|
else:
|
||||||
return f"{base}"
|
return f"{base}"
|
||||||
|
|
||||||
|
|
||||||
class ArgumentParserError(Exception): pass
|
class ArgumentParserError(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -575,7 +577,7 @@ class BServer:
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
self._cache[("Gallery", lang_name)] = [s.encode("utf-8") for s in result]
|
self._cache[("Gallery", lang_name)] = [s.encode("utf-8") for s in result]
|
||||||
return self._cache[("Gallery", lang_name)]
|
return self._cache[("Gallery", lang_name)]
|
||||||
|
|
||||||
|
@ -654,7 +656,7 @@ class BServer:
|
||||||
if render == "3":
|
if render == "3":
|
||||||
http_headers = [('Content-type', 'image/png')]
|
http_headers = [('Content-type', 'image/png')]
|
||||||
http_headers.append(('X-Robots-Tag', 'noindex,nofollow'))
|
http_headers.append(('X-Robots-Tag', 'noindex,nofollow'))
|
||||||
qr_format="png"
|
qr_format = "png"
|
||||||
fn = (box.__class__.__name__)
|
fn = (box.__class__.__name__)
|
||||||
start_response(status, http_headers)
|
start_response(status, http_headers)
|
||||||
qrcode = get_qrcode(box.metadata["url_short"], qr_format)
|
qrcode = get_qrcode(box.metadata["url_short"], qr_format)
|
||||||
|
@ -671,6 +673,7 @@ class BServer:
|
||||||
os.remove(box.output)
|
os.remove(box.output)
|
||||||
return (l for l in result)
|
return (l for l in result)
|
||||||
|
|
||||||
|
|
||||||
def get_qrcode(url, format):
|
def get_qrcode(url, format):
|
||||||
if url is None:
|
if url is None:
|
||||||
url = "no url"
|
url = "no url"
|
||||||
|
@ -679,6 +682,7 @@ def get_qrcode(url, format):
|
||||||
img.save(image_bytes, format=format)
|
img.save(image_bytes, format=format)
|
||||||
return image_bytes.getvalue()
|
return image_bytes.getvalue()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue