mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Ignore --fast-startup flag, assume true
Change-Id: I7a41160bf7f5bb403177b19613de2889e0fa2b44 Reviewed-on: https://dart-review.googlesource.com/c/87424 Reviewed-by: Sigmund Cherem <sigmund@google.com>
This commit is contained in:
parent
aeb7fccd5b
commit
651d19cdaa
|
@ -32,6 +32,13 @@
|
||||||
|
|
||||||
#### dart2js
|
#### dart2js
|
||||||
|
|
||||||
|
* `--fast-startup` is forced on. The flag is silently ignored and will be
|
||||||
|
deprecated and then removed at a later date.
|
||||||
|
|
||||||
|
The alternative 'full emitter' is no longer available. The generated code for
|
||||||
|
`--fast-startup` is optimized to load faster, even though it can be slightly
|
||||||
|
larger.
|
||||||
|
|
||||||
* We fixed a bug in how deferred constructor calls were incorrectly not
|
* We fixed a bug in how deferred constructor calls were incorrectly not
|
||||||
marked as deferred. The old behavior didn't cause breakages, but was imprecise
|
marked as deferred. The old behavior didn't cause breakages, but was imprecise
|
||||||
and pushed more code to the main output unit.
|
and pushed more code to the main output unit.
|
||||||
|
|
|
@ -340,7 +340,7 @@ Future<api.CompilationResult> compile(List<String> argv,
|
||||||
new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
|
new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
|
||||||
new OptionHandler('-O.*', setOptimizationLevel),
|
new OptionHandler('-O.*', setOptimizationLevel),
|
||||||
new OptionHandler(Flags.allowMockCompilation, ignoreOption),
|
new OptionHandler(Flags.allowMockCompilation, ignoreOption),
|
||||||
new OptionHandler(Flags.fastStartup, passThrough),
|
new OptionHandler(Flags.fastStartup, ignoreOption),
|
||||||
new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
|
new OptionHandler(Flags.genericMethodSyntax, ignoreOption),
|
||||||
new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
|
new OptionHandler(Flags.initializingFormalAccess, ignoreOption),
|
||||||
new OptionHandler(Flags.minify, passThrough),
|
new OptionHandler(Flags.minify, passThrough),
|
||||||
|
|
|
@ -387,12 +387,13 @@ class JavaScriptBackend {
|
||||||
|
|
||||||
JavaScriptBackend(this.compiler,
|
JavaScriptBackend(this.compiler,
|
||||||
{bool generateSourceMap: true,
|
{bool generateSourceMap: true,
|
||||||
bool useStartupEmitter: false,
|
bool useStartupEmitter: true,
|
||||||
bool useMultiSourceInfo: false,
|
bool useMultiSourceInfo: false,
|
||||||
bool useNewSourceInfo: false})
|
bool useNewSourceInfo: false})
|
||||||
: this.sourceInformationStrategy =
|
: this.sourceInformationStrategy =
|
||||||
compiler.backendStrategy.sourceInformationStrategy,
|
compiler.backendStrategy.sourceInformationStrategy,
|
||||||
constantCompilerTask = new JavaScriptConstantTask(compiler) {
|
constantCompilerTask = new JavaScriptConstantTask(compiler) {
|
||||||
|
useStartupEmitter = true;
|
||||||
CommonElements commonElements = compiler.frontendStrategy.commonElements;
|
CommonElements commonElements = compiler.frontendStrategy.commonElements;
|
||||||
_backendUsageBuilder =
|
_backendUsageBuilder =
|
||||||
new BackendUsageBuilderImpl(compiler.frontendStrategy);
|
new BackendUsageBuilderImpl(compiler.frontendStrategy);
|
||||||
|
|
|
@ -244,9 +244,9 @@ class CompilerOptions implements DiagnosticOptions {
|
||||||
/// (experimental)
|
/// (experimental)
|
||||||
bool useNewSourceInfo = false;
|
bool useNewSourceInfo = false;
|
||||||
|
|
||||||
/// Whether the user requested to use the fast startup emitter. The full
|
/// Whether the user requested to use the fast startup emitter. Always `true`.
|
||||||
/// emitter might still be used if the program uses dart:mirrors.
|
// TODO(sra): Remove.
|
||||||
bool useStartupEmitter = false;
|
bool useStartupEmitter = true;
|
||||||
|
|
||||||
/// Enable verbose printing during compilation. Includes a time-breakdown
|
/// Enable verbose printing during compilation. Includes a time-breakdown
|
||||||
/// between phases at the end.
|
/// between phases at the end.
|
||||||
|
@ -358,7 +358,7 @@ class CompilerOptions implements DiagnosticOptions {
|
||||||
!_hasOption(options, Flags.noFrequencyBasedMinification)
|
!_hasOption(options, Flags.noFrequencyBasedMinification)
|
||||||
..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo)
|
..useMultiSourceInfo = _hasOption(options, Flags.useMultiSourceInfo)
|
||||||
..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo)
|
..useNewSourceInfo = _hasOption(options, Flags.useNewSourceInfo)
|
||||||
..useStartupEmitter = _hasOption(options, Flags.fastStartup)
|
..useStartupEmitter = true
|
||||||
..verbose = _hasOption(options, Flags.verbose)
|
..verbose = _hasOption(options, Flags.verbose)
|
||||||
..showInternalProgress = _hasOption(options, Flags.progress)
|
..showInternalProgress = _hasOption(options, Flags.progress)
|
||||||
..readDataUri = _extractUriOption(options, '${Flags.readData}=')
|
..readDataUri = _extractUriOption(options, '${Flags.readData}=')
|
||||||
|
@ -390,6 +390,8 @@ class CompilerOptions implements DiagnosticOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
void deriveOptions() {
|
void deriveOptions() {
|
||||||
|
useStartupEmitter = true;
|
||||||
|
|
||||||
if (benchmarkingProduction) {
|
if (benchmarkingProduction) {
|
||||||
useStartupEmitter = true;
|
useStartupEmitter = true;
|
||||||
trustPrimitives = true;
|
trustPrimitives = true;
|
||||||
|
|
|
@ -66,14 +66,14 @@ main() {
|
||||||
|
|
||||||
twoClasses() async {
|
twoClasses() async {
|
||||||
String generated = await compileAll(TEST_ONE);
|
String generated = await compileAll(TEST_ONE);
|
||||||
Expect.isTrue(generated.contains(new RegExp('A: {[ \n]*"\\^": "Object;"')));
|
Expect.isTrue(generated.contains('A: function A()'));
|
||||||
Expect.isTrue(generated.contains(new RegExp('B: {[ \n]*"\\^": "Object;"')));
|
Expect.isTrue(generated.contains('B: function B()'));
|
||||||
}
|
}
|
||||||
|
|
||||||
subClass() async {
|
subClass() async {
|
||||||
checkOutput(String generated) {
|
checkOutput(String generated) {
|
||||||
Expect.isTrue(generated.contains(new RegExp('A: {[ \n]*"\\^": "Object;"')));
|
Expect.isTrue(generated.contains(RegExp(r'_inherit\(.\.A, .\.Object\)')));
|
||||||
Expect.isTrue(generated.contains(new RegExp('B: {[ \n]*"\\^": "A;"')));
|
Expect.isTrue(generated.contains(RegExp(r'_inherit\(.\.B, .\.A\)')));
|
||||||
}
|
}
|
||||||
|
|
||||||
checkOutput(await compileAll(TEST_TWO));
|
checkOutput(await compileAll(TEST_TWO));
|
||||||
|
@ -82,12 +82,15 @@ subClass() async {
|
||||||
|
|
||||||
fieldTest() async {
|
fieldTest() async {
|
||||||
String generated = await compileAll(TEST_FOUR);
|
String generated = await compileAll(TEST_FOUR);
|
||||||
Expect.isTrue(generated
|
Expect.isTrue(generated.contains(RegExp(r'B: function B\(t0, t1, t2\) {'
|
||||||
.contains(new RegExp('B: {[ \n]*"\\^": "A;y,z,x",[ \n]*static:')));
|
r'\s*this.y = t0;'
|
||||||
|
r'\s*this.z = t1;'
|
||||||
|
r'\s*this.x = t2;')));
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor1() async {
|
constructor1() async {
|
||||||
String generated = await compileAll(TEST_FIVE);
|
String generated = await compileAll(TEST_FIVE);
|
||||||
|
print('--------------------\n$generated\n');
|
||||||
Expect.isTrue(generated.contains(new RegExp(r"new [$A-Z]+\.A\(a\);")));
|
Expect.isTrue(generated.contains(new RegExp(r"new [$A-Z]+\.A\(a\);")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,24 +108,22 @@ main() {
|
||||||
main() {
|
main() {
|
||||||
runTests() async {
|
runTests() async {
|
||||||
await compile(TEST_ONE, entry: 'foo', check: (String generated) {
|
await compile(TEST_ONE, entry: 'foo', check: (String generated) {
|
||||||
RegExp regexp = new RegExp(r"1 \+ [a-z]+");
|
RegExp regexp = RegExp(r"1 \+ [a-z]+");
|
||||||
checkNumberOfMatches(regexp.allMatches(generated).iterator, 1);
|
checkNumberOfMatches(regexp.allMatches(generated).iterator, 1);
|
||||||
});
|
});
|
||||||
await compile(TEST_TWO, entry: 'foo', check: (String generated) {
|
await compile(TEST_TWO, entry: 'foo', check: (String generated) {
|
||||||
checkNumberOfMatches(
|
checkNumberOfMatches(RegExp("length").allMatches(generated).iterator, 1);
|
||||||
new RegExp("length").allMatches(generated).iterator, 1);
|
|
||||||
});
|
});
|
||||||
await compile(TEST_THREE, entry: 'foo', check: (String generated) {
|
await compile(TEST_THREE, entry: 'foo', check: (String generated) {
|
||||||
checkNumberOfMatches(
|
checkNumberOfMatches(RegExp("number").allMatches(generated).iterator, 1);
|
||||||
new RegExp("number").allMatches(generated).iterator, 1);
|
|
||||||
});
|
});
|
||||||
await compile(TEST_FOUR, entry: 'foo', check: (String generated) {
|
await compile(TEST_FOUR, entry: 'foo', check: (String generated) {
|
||||||
checkNumberOfMatches(new RegExp("shr").allMatches(generated).iterator, 1);
|
checkNumberOfMatches(RegExp("shr").allMatches(generated).iterator, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
await compileAll(TEST_FIVE).then((generated) {
|
await compileAll(TEST_FIVE).then((generated) {
|
||||||
checkNumberOfMatches(
|
checkNumberOfMatches(
|
||||||
new RegExp("get\\\$foo").allMatches(generated).iterator, 1);
|
RegExp(r"get\$foo\(").allMatches(generated).iterator, 1);
|
||||||
});
|
});
|
||||||
await compileAll(TEST_SIX).then((generated) {
|
await compileAll(TEST_SIX).then((generated) {
|
||||||
Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
|
Expect.isTrue(generated.contains('for (t1 = a.field === 54; t1;)'));
|
||||||
|
|
|
@ -20,9 +20,8 @@ main() {
|
||||||
main() {
|
main() {
|
||||||
runTest() async {
|
runTest() async {
|
||||||
String generated = await compileAll(TEST);
|
String generated = await compileAll(TEST);
|
||||||
|
// No methods (including no constructor body method.
|
||||||
Expect.isTrue(generated
|
Expect.isTrue(generated.contains('.A.prototype = {}'));
|
||||||
.contains(new RegExp('A: {[ \n]*"\\^": "Object;",[ \n]*static:')));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncTest(() async {
|
asyncTest(() async {
|
||||||
|
|
|
@ -18,9 +18,14 @@ main() {
|
||||||
main() {
|
main() {
|
||||||
runTest() async {
|
runTest() async {
|
||||||
String generated = await compileAll(CODE);
|
String generated = await compileAll(CODE);
|
||||||
RegExp regexp = new RegExp(r'\A: {[ \n]*"\^": "[A-Za-z]+;"');
|
|
||||||
|
RegExp regexp = RegExp(r'\.A\.prototype = {');
|
||||||
Iterator<Match> matches = regexp.allMatches(generated).iterator;
|
Iterator<Match> matches = regexp.allMatches(generated).iterator;
|
||||||
checkNumberOfMatches(matches, 1);
|
checkNumberOfMatches(matches, 1);
|
||||||
|
|
||||||
|
RegExp regexp2 = RegExp(r'A\$\w+: function');
|
||||||
|
Iterator<Match> matches2 = regexp2.allMatches(generated).iterator;
|
||||||
|
checkNumberOfMatches(matches2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
asyncTest(() async {
|
asyncTest(() async {
|
||||||
|
|
|
@ -57,7 +57,8 @@ void main() {
|
||||||
|
|
||||||
// Test that inlineSameContext was inlined into lib1.
|
// Test that inlineSameContext was inlined into lib1.
|
||||||
RegExp re4 = new RegExp(r"inline same context");
|
RegExp re4 = new RegExp(r"inline same context");
|
||||||
Expect.isFalse(re4.hasMatch(lib3Output));
|
// Output can be null when it contains no code.
|
||||||
|
Expect.isTrue(lib3Output == null || !re4.hasMatch(lib3Output));
|
||||||
Expect.isTrue(re4.hasMatch(lib1Output));
|
Expect.isTrue(re4.hasMatch(lib1Output));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
||||||
// for details. All rights reserved. Use of this source code is governed by a
|
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
library dart2js.test.uri_retention_test;
|
|
||||||
|
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:async_helper/async_helper.dart';
|
|
||||||
import 'package:compiler/compiler_new.dart';
|
|
||||||
import 'package:compiler/src/commandline_options.dart';
|
|
||||||
import 'package:expect/expect.dart';
|
|
||||||
import '../helpers/memory_compiler.dart' show runCompiler, OutputCollector;
|
|
||||||
|
|
||||||
Future<String> compileSources(sources, {bool minify}) async {
|
|
||||||
var options = <String>[];
|
|
||||||
if (minify) options.add(Flags.minify);
|
|
||||||
OutputCollector outputCollector = new OutputCollector();
|
|
||||||
await runCompiler(
|
|
||||||
memorySourceFiles: sources,
|
|
||||||
options: options,
|
|
||||||
outputProvider: outputCollector);
|
|
||||||
return outputCollector.getOutput('', OutputType.js);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future test(sources, {bool libName, bool fileName}) {
|
|
||||||
return compileSources(sources, minify: false).then((output) {
|
|
||||||
// Unminified the sources should always contain the library name and the
|
|
||||||
// file name.
|
|
||||||
Expect.isTrue(output.contains("main_lib"));
|
|
||||||
Expect.isTrue(output.contains("main.dart"));
|
|
||||||
}).then((_) {
|
|
||||||
compileSources(sources, minify: true).then((output) {
|
|
||||||
Expect.equals(libName, output.contains("main_lib"));
|
|
||||||
Expect.isFalse(output.contains("main.dart"));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
runTests() async {
|
|
||||||
await test(MEMORY_SOURCE_FILES1, libName: false, fileName: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
asyncTest(() async {
|
|
||||||
print('--test from kernel------------------------------------------------');
|
|
||||||
await runTests();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const MEMORY_SOURCE_FILES1 = const <String, String>{
|
|
||||||
'main.dart': """
|
|
||||||
library main_lib;
|
|
||||||
|
|
||||||
class A {
|
|
||||||
final uri = "foo";
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
|
||||||
print(Uri.base);
|
|
||||||
print(new A().uri);
|
|
||||||
}
|
|
||||||
""",
|
|
||||||
};
|
|
|
@ -8,7 +8,7 @@ import 'package:meta/dart2js.dart';
|
||||||
test(o) => o is Function();
|
test(o) => o is Function();
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
test(/*checks=[],functionType,instance*/ () {});
|
test(/*checks=[$signature],instance*/ () {});
|
||||||
test(
|
test(
|
||||||
|
|
||||||
/*strong.checks=[],instance*/
|
/*strong.checks=[],instance*/
|
||||||
|
|
|
@ -13,7 +13,7 @@ class A<T> {
|
||||||
|
|
||||||
@NoInline()
|
@NoInline()
|
||||||
f() {
|
f() {
|
||||||
return /*checks=[],functionType,instance*/ (int t) {};
|
return /*checks=[$signature],instance*/ (int t) {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// BSD-style license that can be found in the LICENSE file.
|
// BSD-style license that can be found in the LICENSE file.
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
T id<T>(T t) => t;
|
T id<T>(T t) => t;
|
||||||
int Function(int) x = id;
|
int Function(int) x = id;
|
||||||
|
|
|
@ -53,50 +53,50 @@ typedef okWithDynamicFunc_2({int x, bool y, List<Map> z, classesFunc v});
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({D a, B b, C c, A d}) {} is classesFunc);
|
({D a, B b, C c, A d}) {} is classesFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*checks=[],functionType,instance*/
|
/*checks=[$signature],instance*/
|
||||||
({A a, A b, A c, A d}) {} is classesFunc);
|
({A a, A b, A c, A d}) {} is classesFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({D a, A1 b, A1 c, A1 d}) {} is classesFunc);
|
({D a, A1 b, A1 c, A1 d}) {} is classesFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({D a, A2 b, A2 c, A2 d}) {} is classesFunc);
|
({D a, A2 b, A2 c, A2 d}) {} is classesFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({D a, D b, D c, D d}) {} is classesFunc);
|
({D a, D b, D c, D d}) {} is classesFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*checks=[],functionType,instance*/
|
/*checks=[$signature],instance*/
|
||||||
({var a, var b, var c, var d}) {} is classesFunc);
|
({var a, var b, var c, var d}) {} is classesFunc);
|
||||||
Expect.isTrue(/*checks=[],functionType,instance*/
|
Expect.isTrue(/*checks=[$signature],instance*/
|
||||||
({Object a, Object b, Object c, Object d}) {} is classesFunc);
|
({Object a, Object b, Object c, Object d}) {} is classesFunc);
|
||||||
|
|
||||||
Expect.isTrue(/*checks=[],functionType,instance*/
|
Expect.isTrue(/*checks=[$signature],instance*/
|
||||||
({Map<num, num> m, List<List<A1>> l, G<A, A1, A1, A1> g}) {}
|
({Map<num, num> m, List<List<A1>> l, G<A, A1, A1, A1> g}) {}
|
||||||
is genericsFunc);
|
is genericsFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({Map<int, int> m, List<List<D>> l, G<D, D, D, D> g}) {} is genericsFunc);
|
({Map<int, int> m, List<List<D>> l, G<D, D, D, D> g}) {} is genericsFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*checks=[],functionType,instance*/
|
/*checks=[$signature],instance*/
|
||||||
({var m, var l, var g}) {} is genericsFunc);
|
({var m, var l, var g}) {} is genericsFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*checks=[],functionType,instance*/
|
/*checks=[$signature],instance*/
|
||||||
({Object m, Object l, Object g}) {} is genericsFunc);
|
({Object m, Object l, Object g}) {} is genericsFunc);
|
||||||
|
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({A x, G y, mixFunc z, var v}) {} is dynamicFunc);
|
({A x, G y, mixFunc z, var v}) {} is dynamicFunc);
|
||||||
Expect.isTrue(
|
Expect.isTrue(
|
||||||
/*strong.checks=[],functionType,instance*/
|
/*strong.checks=[$signature],instance*/
|
||||||
/*omit.checks=[],instance*/
|
/*omit.checks=[],instance*/
|
||||||
({int x, bool y, List<Map> z, classesFunc v}) {} is dynamicFunc);
|
({int x, bool y, List<Map> z, classesFunc v}) {} is dynamicFunc);
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ main() {
|
||||||
{okWithClassesFunc_1 f1,
|
{okWithClassesFunc_1 f1,
|
||||||
okWithGenericsFunc_1 f2,
|
okWithGenericsFunc_1 f2,
|
||||||
okWithDynamicFunc_1 f3}) {} is funcFunc);
|
okWithDynamicFunc_1 f3}) {} is funcFunc);
|
||||||
Expect.isTrue(/*checks=[],functionType,instance*/
|
Expect.isTrue(/*checks=[$signature],instance*/
|
||||||
(
|
(
|
||||||
{okWithClassesFunc_2 f1,
|
{okWithClassesFunc_2 f1,
|
||||||
okWithGenericsFunc_2 f2,
|
okWithGenericsFunc_2 f2,
|
||||||
|
|
Loading…
Reference in a new issue