glo->defineDefaultProperty(rootContext, QStringLiteral("parseFloat"), Value::fromObject(new (memoryManager) ParseFloatFunction(rootContext)));
glo->defineDefaultProperty(rootContext, QStringLiteral("isNaN"), Value::fromObject(new (memoryManager) IsNaNFunction(rootContext)));
glo->defineDefaultProperty(rootContext, QStringLiteral("isFinite"), Value::fromObject(new (memoryManager) IsFiniteFunction(rootContext)));
+ glo->defineDefaultProperty(rootContext, QStringLiteral("decodeURI"), Value::fromObject(new (memoryManager) DecodeUriFunction(rootContext)));
+ glo->defineDefaultProperty(rootContext, QStringLiteral("decodeURIComponent"), Value::fromObject(new (memoryManager) DecodeUriComponentFunction(rootContext)));
+ glo->defineDefaultProperty(rootContext, QStringLiteral("encodeURI"), Value::fromObject(new (memoryManager) EncodeUriFunction(rootContext)));
+ glo->defineDefaultProperty(rootContext, QStringLiteral("encodeURIComponent"), Value::fromObject(new (memoryManager) EncodeUriComponentFunction(rootContext)));
}
ExecutionEngine::~ExecutionEngine()
return new (memoryManager) RangeErrorObject(ctx, message);
}
+Object *ExecutionEngine::newURIErrorObject(ExecutionContext *ctx, Value message)
+{
+ return new (memoryManager) URIErrorObject(ctx, message);
+}
+
Object *ExecutionEngine::newMathObject(ExecutionContext *ctx)
{
MathObject *object = new (memoryManager) MathObject(ctx);
Object *newReferenceErrorObject(ExecutionContext *ctx, const QString &message);
Object *newTypeErrorObject(ExecutionContext *ctx, const QString &message);
Object *newRangeErrorObject(ExecutionContext *ctx, const QString &message);
+ Object *newURIErrorObject(ExecutionContext *ctx, Value message);
Object *newMathObject(ExecutionContext *ctx);
Object *newActivationObject();
throwError(Value::fromObject(engine->newRangeErrorObject(this, msg)));
}
+void ExecutionContext::throwURIError(Value msg)
+{
+ throwError(Value::fromObject(engine->newURIErrorObject(this, msg)));
+}
+
void ExecutionContext::initCallContext(ExecutionContext *parent, const Value that, FunctionObject *f, Value *args, unsigned argc)
{
MemoryManager::GCBlocker blockGC(parent->engine->memoryManager);
void throwTypeError();
void throwReferenceError(Value value);
void throwRangeError(Value value);
+ void throwURIError(Value msg);
void throwUnimplemented(const QString &message);
void setProperty(String *name, Value value);
prototype = ctx->engine->uRIErrorPrototype;
}
+URIErrorObject::URIErrorObject(ExecutionContext *ctx, Value msg)
+ : ErrorObject(ctx->engine, msg)
+{
+ setNameProperty(ctx);
+ prototype = ctx->engine->uRIErrorPrototype;
+}
+
ErrorCtor::ErrorCtor(ExecutionContext *scope)
: FunctionObject(scope)
struct URIErrorObject: ErrorObject {
URIErrorObject(ExecutionContext *ctx);
+ URIErrorObject(ExecutionContext *ctx, Value);
virtual QString className() { return QStringLiteral("URIError"); }
};
****************************************************************************/
#include "qv4globalobject.h"
-#include "qv4ir_p.h"
-#include "qv4isel_p.h"
-#include "qv4objectproto.h"
-#include "qv4stringobject.h"
#include "qv4mm.h"
+#include "qmljs_value.h"
+#include "qmljs_environment.h"
#include <private/qqmljsengine_p.h>
#include <private/qqmljslexer_p.h>
#include <qv4codegen_p.h>
#include "private/qlocale_tools_p.h"
-#include <QtCore/qmath.h>
#include <QtCore/QDebug>
-#include <cassert>
-#include <typeinfo>
+#include <QtCore/QString>
#include <iostream>
-#include <alloca.h>
using namespace QQmlJS::VM;
+static inline char toHex(char c)
+{
+ static const char hexnumbers[] = "0123456789ABCDEF";
+ return hexnumbers[c & 0xf];
+}
+
+static int fromHex(QChar ch)
+{
+ ushort c = ch.unicode();
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+ return -1;
+}
+
+static QString escape(const QString &input)
+{
+ QString output;
+ output.reserve(input.size() * 3);
+ const int length = input.length();
+ for (int i = 0; i < length; ++i) {
+ ushort uc = input.at(i).unicode();
+ if (uc < 0x100) {
+ if ( (uc > 0x60 && uc < 0x7B)
+ || (uc > 0x3F && uc < 0x5B)
+ || (uc > 0x2C && uc < 0x3A)
+ || (uc == 0x2A)
+ || (uc == 0x2B)
+ || (uc == 0x5F)) {
+ output.append(QChar(uc));
+ } else {
+ output.append('%');
+ output.append(QChar(toHex(uc >> 4)));
+ output.append(QChar(toHex(uc)));
+ }
+ } else {
+ output.append('%');
+ output.append('u');
+ output.append(QChar(toHex(uc >> 12)));
+ output.append(QChar(toHex(uc >> 8)));
+ output.append(QChar(toHex(uc >> 4)));
+ output.append(QChar(toHex(uc)));
+ }
+ }
+ return output;
+}
+
+static QString unescape(const QString &input)
+{
+ QString result;
+ result.reserve(input.length());
+ int i = 0;
+ const int length = input.length();
+ while (i < length) {
+ QChar c = input.at(i++);
+ if ((c == '%') && (i + 1 < length)) {
+ QChar a = input.at(i);
+ if ((a == 'u') && (i + 4 < length)) {
+ int d3 = fromHex(input.at(i+1));
+ int d2 = fromHex(input.at(i+2));
+ int d1 = fromHex(input.at(i+3));
+ int d0 = fromHex(input.at(i+4));
+ if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) {
+ ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0);
+ result.append(QChar(uc));
+ i += 5;
+ } else {
+ result.append(c);
+ }
+ } else {
+ int d1 = fromHex(a);
+ int d0 = fromHex(input.at(i+1));
+ if ((d1 != -1) && (d0 != -1)) {
+ c = (d1 << 4) | d0;
+ i += 2;
+ }
+ result.append(c);
+ }
+ } else {
+ result.append(c);
+ }
+ }
+ return result;
+}
+
+static const char uriReserved[] = ";/?:@&=+$,";
+static const char uriUnescaped[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.!~*'()";
+
+static QString encode(const QString &input, const QString &unescapedSet, bool *ok)
+{
+ *ok = true;
+ QString output;
+ const int length = input.length();
+ int i = 0;
+ while (i < length) {
+ const QChar c = input.at(i);
+ if (!unescapedSet.contains(c)) {
+ ushort uc = c.unicode();
+ if ((uc >= 0xDC00) && (uc <= 0xDFFF)) {
+ *ok = false;
+ break;
+ }
+ if (!((uc < 0xD800) || (uc > 0xDBFF))) {
+ ++i;
+ if (i == length) {
+ *ok = false;
+ break;
+ }
+ const ushort uc2 = input.at(i).unicode();
+ if ((uc < 0xDC00) || (uc > 0xDFFF)) {
+ *ok = false;
+ break;
+ }
+ uc = ((uc - 0xD800) * 0x400) + (uc2 - 0xDC00) + 0x10000;
+ }
+ QString tmp(1, QChar(uc));
+ QByteArray octets = tmp.toUtf8();
+ for (int j = 0; j < octets.length(); ++j) {
+ output.append(QLatin1Char('%'));
+ output.append(QLatin1Char(toHex(octets.at(j) >> 4)));
+ output.append(QLatin1Char(toHex(octets.at(j))));
+ }
+ } else {
+ output.append(c);
+ }
+ ++i;
+ }
+ if (i != length)
+ *ok = false;
+ return output;
+}
+
+static QString decode(const QString &input, const QString &reservedSet, bool *ok)
+{
+ *ok = true;
+ QString output;
+ const int length = input.length();
+ int i = 0;
+ const QChar percent = QLatin1Char('%');
+ while (i < length) {
+ const QChar ch = input.at(i);
+ if (ch == percent) {
+ int start = i;
+ if (i + 2 >= length)
+ goto error;
+
+ int d1 = fromHex(input.at(i+1));
+ int d0 = fromHex(input.at(i+2));
+ if ((d1 == -1) || (d0 == -1))
+ goto error;
+
+ int b = (d1 << 4) | d0;
+ i += 2;
+ if (b & 0x80) {
+ int uc;
+ int min_uc;
+ int need;
+ if ((b & 0xe0) == 0xc0) {
+ uc = b & 0x1f;
+ need = 1;
+ min_uc = 0x80;
+ } else if ((b & 0xf0) == 0xe0) {
+ uc = b & 0x0f;
+ need = 2;
+ min_uc = 0x800;
+ } else if ((b & 0xf8) == 0xf0) {
+ uc = b & 0x07;
+ need = 3;
+ min_uc = 0x10000;
+ } else {
+ goto error;
+ }
+
+ if (i + (3 * need) >= length)
+ goto error;
+
+ for (int j = 0; j < need; ++j) {
+ ++i;
+ if (input.at(i) != percent)
+ goto error;
+
+ d1 = fromHex(input.at(i+1));
+ d0 = fromHex(input.at(i+2));
+ if ((d1 == -1) || (d0 == -1))
+ goto error;
+
+ b = (d1 << 4) | d0;
+ if ((b & 0xC0) != 0x80)
+ goto error;
+
+ i += 2;
+ uc = (uc << 6) + b;
+ }
+ if (uc < min_uc)
+ goto error;
+
+ if (uc < 0x10000) {
+ output.append(QChar(uc));
+ } else {
+ if (uc > 0x10FFFF)
+ goto error;
+
+ ushort l = ushort(((uc - 0x10000) & 0x3FF) + 0xDC00);
+ ushort h = ushort((((uc - 0x10000) >> 10) & 0x3FF) + 0xD800);
+ output.append(QChar(l));
+ output.append(QChar(h));
+ }
+ } else {
+ QChar z(b);
+ if (!reservedSet.contains(z)) {
+ output.append(z);
+ } else {
+ output.append(input.mid(start, i - start + 1));
+ }
+ }
+ } else {
+ output.append(ch);
+ }
+ ++i;
+ }
+ if (i != length)
+ *ok = false;
+ return output;
+ error:
+ *ok = false;
+ return QString();
+}
+
+
Value EvalFunction::call(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc)
{
double d = v.toNumber(context);
return Value::fromBoolean(std::isfinite(d));
}
+
+
+/// decodeURI [15.1.3.1]
+DecodeUriFunction::DecodeUriFunction(ExecutionContext *scope)
+ : FunctionObject(scope)
+{
+ name = scope->engine->newString(QLatin1String("decodeURI"));
+}
+
+Value DecodeUriFunction::call(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc)
+{
+ if (argc == 0)
+ return Value::undefinedValue();
+
+ QString uriString = args[0].toString(context)->toQString();
+ bool ok;
+ QString out = decode(uriString, QString::fromUtf8(uriReserved) + QString::fromUtf8("#"), &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+/// decodeURIComponent [15.1.3.2]
+DecodeUriComponentFunction::DecodeUriComponentFunction(ExecutionContext *scope)
+ : FunctionObject(scope)
+{
+ name = scope->engine->newString(QLatin1String("decodeURIComponent"));
+}
+
+Value DecodeUriComponentFunction::call(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc)
+{
+ if (argc == 0)
+ return Value::undefinedValue();
+
+ QString uriString = args[0].toString(context)->toQString();
+ bool ok;
+ QString out = decode(uriString, QString(), &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+/// encodeURI [15.1.3.3]
+EncodeUriFunction::EncodeUriFunction(ExecutionContext *scope)
+ : FunctionObject(scope)
+{
+ name = scope->engine->newString(QLatin1String("encodeURI"));
+}
+
+Value EncodeUriFunction::call(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc)
+{
+ if (argc == 0)
+ return Value::undefinedValue();
+
+ QString uriString = args[0].toString(context)->toQString();
+ bool ok;
+ QString out = encode(uriString, QLatin1String(uriReserved) + QLatin1String(uriUnescaped) + QString::fromUtf8("#"), &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+
+/// encodeURIComponent [15.1.3.4]
+EncodeUriComponentFunction::EncodeUriComponentFunction(ExecutionContext *scope)
+ : FunctionObject(scope)
+{
+ name = scope->engine->newString(QLatin1String("encodeURIComponent"));
+}
+
+Value EncodeUriComponentFunction::call(ExecutionContext *context, Value /*thisObject*/, Value *args, int argc)
+{
+ if (argc == 0)
+ return Value::undefinedValue();
+
+ QString uriString = args[0].toString(context)->toQString();
+ bool ok;
+ QString out = encode(uriString, QString(), &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
#ifndef QV4GLOBALOBJECT_H
#define QV4GLOBALOBJECT_H
-#include "qmljs_runtime.h"
-#include "qmljs_engine.h"
-#include "qmljs_environment.h"
#include "qv4functionobject.h"
-#include "qv4array.h"
-#include "qv4string.h"
-#include "qv4codegen_p.h"
-#include "qv4isel_p.h"
-#include "qv4managed.h"
-#include "qv4propertydescriptor.h"
-#include "qv4propertytable.h"
-#include "qv4objectiterator.h"
-#include "qv4regexp.h"
-
-#include <QtCore/QString>
-#include <QtCore/QHash>
-#include <QtCore/QScopedPointer>
-#include <cstdio>
-#include <cassert>
namespace QQmlJS {
namespace VM {
-struct Value;
-struct Function;
-struct Object;
-struct ObjectIterator;
-struct BooleanObject;
-struct NumberObject;
-struct StringObject;
-struct ArrayObject;
-struct DateObject;
-struct FunctionObject;
-struct RegExpObject;
-struct ErrorObject;
-struct ArgumentsObject;
-struct ExecutionContext;
-struct ExecutionEngine;
-class MemoryManager;
-
-struct ObjectPrototype;
-struct StringPrototype;
-struct NumberPrototype;
-struct BooleanPrototype;
-struct ArrayPrototype;
-struct FunctionPrototype;
-struct DatePrototype;
-struct RegExpPrototype;
-struct ErrorPrototype;
-struct EvalErrorPrototype;
-struct RangeErrorPrototype;
-struct ReferenceErrorPrototype;
-struct SyntaxErrorPrototype;
-struct TypeErrorPrototype;
-struct URIErrorPrototype;
-
-
struct EvalFunction : FunctionObject
{
EvalFunction(ExecutionContext *scope);
virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
};
+struct DecodeUriFunction: FunctionObject
+{
+ DecodeUriFunction(ExecutionContext *scope);
+
+ virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
+};
+
+struct DecodeUriComponentFunction: FunctionObject
+{
+ DecodeUriComponentFunction(ExecutionContext *scope);
+
+ virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
+};
+
+struct EncodeUriFunction: FunctionObject
+{
+ EncodeUriFunction(ExecutionContext *scope);
+
+ virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
+};
+
+struct EncodeUriComponentFunction: FunctionObject
+{
+ EncodeUriComponentFunction(ExecutionContext *scope);
+
+ virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc);
+};
+
} // namespace VM
} // namespace QQmlJS
S15.1.3.2_A2.5_T1
# Tests failing that are supposed to pass.
-S10.2.3_A1.1_T2 failing
-S10.2.3_A1.2_T2 failing
-S10.2.3_A1.3_T2 failing
10.4.2-1-1 failing
10.4.2-1-2 failing
10.4.2-1-3 failing
S15.1.2.5_A2.3 failing
S15.1.2.5_A2.4 failing
S15.1.2.5_A2.7 failing
-S15.1.3.1_A1.10_T1 failing
-S15.1.3.1_A1.11_T1 failing
-S15.1.3.1_A1.11_T2 failing
-S15.1.3.1_A1.12_T1 failing
-S15.1.3.1_A1.12_T2 failing
-S15.1.3.1_A1.12_T3 failing
S15.1.3.1_A1.13_T1 failing
S15.1.3.1_A1.13_T2 failing
S15.1.3.1_A1.14_T1 failing
S15.1.3.1_A1.15_T4 failing
S15.1.3.1_A1.15_T5 failing
S15.1.3.1_A1.15_T6 failing
-S15.1.3.1_A1.1_T1 failing
-S15.1.3.1_A1.2_T1 failing
-S15.1.3.1_A1.2_T2 failing
-S15.1.3.1_A1.3_T1 failing
-S15.1.3.1_A1.3_T2 failing
-S15.1.3.1_A1.4_T1 failing
-S15.1.3.1_A1.5_T1 failing
-S15.1.3.1_A1.6_T1 failing
-S15.1.3.1_A1.7_T1 failing
-S15.1.3.1_A1.8_T1 failing
-S15.1.3.1_A1.8_T2 failing
-S15.1.3.1_A1.9_T1 failing
-S15.1.3.1_A1.9_T2 failing
-S15.1.3.1_A1.9_T3 failing
-S15.1.3.1_A2.1_T1 failing
15.12.3-11-2 failing
15.12.3-11-26 failing
15.12.3-11-3 failing
15.12.3_2-3-a-3 failing
15.12.3_4-1-2 failing
S15.1.3.2_A5.4 failing
-S15.1.3.2_A5.6 failing
S15.1.3.2_A5.7 failing
-S15.1.3.2_A6_T1 failing
-S15.1.3.3_A1.1_T1 failing
-S15.1.3.3_A1.1_T2 failing
-S15.1.3.3_A1.2_T1 failing
-S15.1.3.3_A1.2_T2 failing
-S15.1.3.3_A1.3_T1 failing
-S15.1.3.3_A2.1_T1 failing
-S15.1.3.3_A2.2_T1 failing
-S15.1.3.3_A2.3_T1 failing
S15.1.3.3_A2.4_T1 failing
S15.1.3.3_A2.4_T2 failing
S15.1.3.3_A2.5_T1 failing
-S15.1.3.3_A3.1_T1 failing
-S15.1.3.3_A3.2_T1 failing
-S15.1.3.3_A3.2_T2 failing
-S15.1.3.3_A3.2_T3 failing
-S15.1.3.3_A3.3_T1 failing
-S15.1.3.3_A4_T1 failing
-S15.1.3.3_A4_T2 failing
-S15.1.3.3_A4_T3 failing
-S15.1.3.3_A4_T4 failing
S15.1.3.3_A5.1 failing
S15.1.3.3_A5.2 failing
S15.1.3.3_A5.3 failing
S15.1.3.3_A5.4 failing
-S15.1.3.3_A5.6 failing
S15.1.3.3_A5.7 failing
-S15.1.3.3_A6_T1 failing
-S15.1.3.4_A1.1_T1 failing
-S15.1.3.4_A1.1_T2 failing
-S15.1.3.4_A1.2_T1 failing
-S15.1.3.4_A1.2_T2 failing
-S15.1.3.4_A1.3_T1 failing
-S15.1.3.4_A2.1_T1 failing
-S15.1.3.4_A2.2_T1 failing
-S15.1.3.4_A2.3_T1 failing
S15.1.3.4_A2.4_T1 failing
S15.1.3.4_A2.4_T2 failing
S15.1.3.4_A2.5_T1 failing
-S15.1.3.4_A3.1_T1 failing
S15.1.3.4_A3.2_T1 failing
S15.1.3.4_A3.2_T2 failing
S15.1.3.4_A3.2_T3 failing
-S15.1.3.4_A3.3_T1 failing
S15.1.3.4_A4_T1 failing
S15.1.3.4_A4_T2 failing
S15.1.3.4_A4_T3 failing
S15.1.3.4_A5.2 failing
S15.1.3.4_A5.3 failing
S15.1.3.4_A5.4 failing
-S15.1.3.4_A5.6 failing
S15.1.3.4_A5.7 failing
S15.1.3.4_A6_T1 failing
-S15.1.3.1_A2.2_T1 failing
S15.1.3.1_A2.3_T1 failing
S15.1.3.1_A2.4_T1 failing
-S15.1.3.1_A3_T1 failing
-S15.1.3.1_A3_T2 failing
-S15.1.3.1_A3_T3 failing
-S15.1.3.1_A4_T1 failing
S15.1.3.1_A4_T2 failing
-S15.1.3.1_A4_T3 failing
-S15.1.3.1_A4_T4 failing
S15.1.3.1_A5.1 failing
S15.1.3.1_A5.2 failing
S15.1.3.1_A5.3 failing
S15.1.3.1_A5.4 failing
-S15.1.3.1_A5.6 failing
S15.1.3.1_A5.7 failing
-S15.1.3.1_A6_T1 failing
-S15.1.3.2_A1.10_T1 failing
-S15.1.3.2_A1.11_T1 failing
-S15.1.3.2_A1.11_T2 failing
-S15.1.3.2_A1.12_T1 failing
-S15.1.3.2_A1.12_T2 failing
-S15.1.3.2_A1.12_T3 failing
S15.1.3.2_A1.13_T1 failing
S15.1.3.2_A1.13_T2 failing
S15.1.3.2_A1.14_T1 failing
S15.1.3.2_A1.15_T4 failing
S15.1.3.2_A1.15_T5 failing
S15.1.3.2_A1.15_T6 failing
-S15.1.3.2_A1.1_T1 failing
-S15.1.3.2_A1.2_T1 failing
-S15.1.3.2_A1.2_T2 failing
-S15.1.3.2_A1.3_T1 failing
-S15.1.3.2_A1.3_T2 failing
-S15.1.3.2_A1.4_T1 failing
-S15.1.3.2_A1.5_T1 failing
-S15.1.3.2_A1.6_T1 failing
-S15.1.3.2_A1.7_T1 failing
-S15.1.3.2_A1.8_T1 failing
-S15.1.3.2_A1.8_T2 failing
-S15.1.3.2_A1.9_T1 failing
-S15.1.3.2_A1.9_T2 failing
-S15.1.3.2_A1.9_T3 failing
-S15.1.3.2_A2.1_T1 failing
-S15.1.3.2_A2.2_T1 failing
S15.1.3.2_A2.3_T1 failing
S15.1.3.2_A2.4_T1 failing
-S15.1.3.2_A3_T1 failing
-S15.1.3.2_A3_T2 failing
-S15.1.3.2_A3_T3 failing
-S15.1.3.2_A4_T1 failing
S15.1.3.2_A4_T2 failing
-S15.1.3.2_A4_T3 failing
-S15.1.3.2_A4_T4 failing
S15.1.3.2_A5.1 failing
S15.1.3.2_A5.2 failing
S15.1.3.2_A5.3 failing
-15.2.3.3-4-10 failing
-15.2.3.3-4-11 failing
15.2.3.3-4-12 failing
15.2.3.3-4-13 failing
-15.2.3.3-4-9 failing
15.2.3.6-2-17-1 failing
15.2.3.6-4-291-1 failing
15.2.3.6-4-292-1 failing
15.12.3-11-23 failing
15.12.3-11-24 failing
15.12.3-11-25 failing
-15.2.3.4-4-1 failing
15.4.4.18-7-c-i-6 failing
15.4.4.19-8-c-i-6 failing
15.4.4.20-9-c-i-6 failing
15.4.4.21-8-b-iii-1-6 failing
15.12.3_4-1-1
-15.12.3_4-1-3
\ No newline at end of file
+15.12.3_4-1-3