From 860a77cfcd1ee38f10f0f1c7af759bf5218dfdd5 Mon Sep 17 00:00:00 2001 From: Lahiru Madushanka Date: Tue, 29 Oct 2024 09:15:39 +0530 Subject: [PATCH] Introduce SIEL expression support Add new synapse path type called SIEL to evaluate complex expressions which are not supported in either JSONPath or XPATH. Fixes wso2/micro-integrator/issues/3749 --- modules/core/pom.xml | 42 ++ .../synapse/util/SIEL/ExpressionLexer.g4 | 110 ++++ .../synapse/util/SIEL/ExpressionParser.g4 | 174 ++++++ .../util/SIEL/gen/ExpressionLexer.interp | 231 ++++++++ .../util/SIEL/gen/ExpressionLexer.java | 554 ++++++++++++++++++ .../util/SIEL/gen/ExpressionLexer.tokens | 129 ++++ .../org/apache/synapse/SynapseConstants.java | 54 ++ .../config/xml/PropertyMediatorFactory.java | 5 + .../synapse/config/xml/SynapsePath.java | 7 +- .../config/xml/SynapsePathFactory.java | 4 + .../util/SIEL/ast/ArgumentListNode.java | 46 ++ .../synapse/util/SIEL/ast/ArrayIndexNode.java | 51 ++ .../util/SIEL/ast/BinaryOperationNode.java | 166 ++++++ .../SIEL/ast/ConditionalExpressionNode.java | 50 ++ .../synapse/util/SIEL/ast/ExpressionNode.java | 28 + .../util/SIEL/ast/ExpressionResult.java | 206 +++++++ .../util/SIEL/ast/FilterExpressionNode.java | 60 ++ .../ast/HeadersAndPropertiesAccessNode.java | 66 +++ .../synapse/util/SIEL/ast/LiteralNode.java | 102 ++++ .../util/SIEL/ast/PayloadAccessNode.java | 159 +++++ .../util/SIEL/ast/PredefinedFunctionNode.java | 446 ++++++++++++++ .../util/SIEL/ast/SignedExpressionNode.java | 48 ++ .../util/SIEL/context/EvaluationContext.java | 78 +++ .../SIEL/exception/EvaluationException.java | 11 + .../util/SIEL/exception/SyntaxError.java | 50 ++ .../SIEL/exception/SyntaxErrorListener.java | 70 +++ .../util/SIEL/utils/ExpressionUtils.java | 68 +++ .../util/SIEL/visitor/ExpressionVisitor.java | 400 +++++++++++++ .../synapse/util/xpath/SynapseSIELPath.java | 78 +++ .../util/SIEL/ConditionalExpressionTest.java | 55 ++ .../SIEL/HeaderAndPropertyAccessTest.java | 113 ++++ .../SIEL/PayloadAndVariableAccessTest.java | 142 +++++ .../util/SIEL/PreDefinedFunctionsTest.java | 532 +++++++++++++++++ .../util/SIEL/PrimitiveExpressionsTest.java | 226 +++++++ .../synapse/util/SIEL/SyntaxErrorsTest.java | 55 ++ .../apache/synapse/util/SIEL/TestUtils.java | 175 ++++++ pom.xml | 14 +- 37 files changed, 4802 insertions(+), 3 deletions(-) create mode 100644 modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionLexer.g4 create mode 100644 modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionParser.g4 create mode 100644 modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.interp create mode 100644 modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.java create mode 100644 modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.tokens create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArgumentListNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArrayIndexNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/BinaryOperationNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ConditionalExpressionNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionResult.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/FilterExpressionNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/HeadersAndPropertiesAccessNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/LiteralNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/PayloadAccessNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/PredefinedFunctionNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/SignedExpressionNode.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/context/EvaluationContext.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/exception/EvaluationException.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/exception/SyntaxError.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/exception/SyntaxErrorListener.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/utils/ExpressionUtils.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/SIEL/visitor/ExpressionVisitor.java create mode 100644 modules/core/src/main/java/org/apache/synapse/util/xpath/SynapseSIELPath.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/ConditionalExpressionTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/HeaderAndPropertyAccessTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/PayloadAndVariableAccessTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/PreDefinedFunctionsTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/PrimitiveExpressionsTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/SyntaxErrorsTest.java create mode 100644 modules/core/src/test/java/org/apache/synapse/util/SIEL/TestUtils.java diff --git a/modules/core/pom.xml b/modules/core/pom.xml index f9985835e5..e574dda528 100644 --- a/modules/core/pom.xml +++ b/modules/core/pom.xml @@ -145,6 +145,44 @@ + + org.antlr + antlr4-maven-plugin + + + antlr + generate-sources + + antlr4 + + + ${project.basedir}/src/main/antlr4 + + -visitor + + + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + add-source + generate-sources + + add-source + + + + ${project.build.directory}/generated-sources/antlr4 + + + + + @@ -506,5 +544,9 @@ org.apache.logging.log4j log4j-slf4j-impl + + org.antlr + antlr4-runtime + diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionLexer.g4 b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionLexer.g4 new file mode 100644 index 0000000000..869f7b9064 --- /dev/null +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionLexer.g4 @@ -0,0 +1,110 @@ +lexer grammar ExpressionLexer; + +JSONPATH_FUNCTIONS: 'contains ' | 'in' | 'nin' | 'subsetof' | 'size' | 'empty' | 'empty true' | 'empty false' | '=~'; + +// Tokens for identifiers, operators, and keywords +VAR: 'var'; +PAYLOAD: 'payload' | '$'; +HEADERS: 'headers'; +CONFIG: 'config'; +ATTRIBUTES: 'attributes'; +AXIS2: 'axis2'; +SYNAPSE: 'synapse'; +REGISTRY: 'registry'; +SECRET: 'secret'; +BASE64ENCODE: 'base64encode'; +BASE64DECODE: 'base64decode'; +URLENCODE: 'urlEncode'; +URLDECODE: 'urlDecode'; +NOW: 'now'; +TODAY: 'today'; +FORMATDATE: 'formatDate'; +ISNUMBER: 'isNumber'; +ISSTRING: 'isString'; +ISARRAY: 'isArray'; +ISOBJECT: 'isObject'; +ROUND: 'round'; +INTEGER: 'integer'; +FLOAT: 'float'; +STRING: 'string'; +BOOLEAN: 'boolean'; +ABS: 'abs'; +FLOOR: 'floor'; +CEIL: 'ceil'; +SQRT: 'sqrt'; +LOG: 'log'; +POW: 'pow'; +LENGTH: 'length'; +TOUPPER: 'toUpper'; +TOLOWER: 'toLower'; +SUBSTRING: 'subString'; +STARTSWITH: 'startsWith'; +ENDSWITH: 'endsWith'; +CONTAINS: 'contains'; +TRIM: 'trim'; +REPLACE: 'replace'; +SPLIT: 'split'; +AND: 'and' | '&&'; +OR: 'or' | '||'; +NOT: 'not' | '!'; + +DOUBLE_DOT : '..'; +ASTERISK : '*'; + +// Operators +PLUS: '+'; +MINUS: '-'; +DIV: '/'; +MODULO: '%'; +EQ: '=='; +NEQ: '!='; +GT: '>'; +LT: '<'; +GTE: '>='; +LTE: '<='; + +// Delimiters +LPAREN: '('; +RPAREN: ')'; +LBRACKET: '['; +RBRACKET: ']'; +DOT: '.'; +COMMA: ','; +COLON: ':'; +QUOTE: '"' | '\''; + +// Literals +BOOLEAN_LITERAL: 'true' | 'false'; +NUMBER: '-'? [0-9]+ ('.' [0-9]+)?; + + +STRING_LITERAL : ('"' (ESC | ~["\\])* '"' | '\'' (ESC | ~['\\])* '\''); + + +fragment ESC + : '\\' [btnfr"'\\/] // Basic escape sequences + | UNICODE_ESC + | OCTAL_ESC + ; + +fragment UNICODE_ESC + : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT + ; + +fragment OCTAL_ESC + : '\\' [0-3]? [0-7] [0-7] + ; + +fragment HEX_DIGIT + : [0-9a-fA-F] + ; + +// Identifiers +ID: [a-zA-Z_][a-zA-Z_0-9]*; +GETPROPERTY: 'getProperty'; +// Special symbols for JSONPath filter expressions +QUESTION: '?'; +AT: '@'; + +// Whitespace +WS: [ \t\n\r]+ -> skip; diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionParser.g4 b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionParser.g4 new file mode 100644 index 0000000000..ad339009bd --- /dev/null +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionParser.g4 @@ -0,0 +1,174 @@ +parser grammar ExpressionParser; + +options { + tokenVocab = ExpressionLexer; +} + +expression + : comparisonExpression + | conditionalExpression + | EOF + ; + +conditionalExpression + : comparisonExpression (QUESTION expression COLON expression)? + ; + +comparisonExpression + : logicalExpression ( (GT | LT | GTE | LTE | EQ | NEQ) logicalExpression )* + ; + +logicalExpression + : arithmeticExpression (AND logicalExpression | OR logicalExpression)? + ; + +arithmeticExpression + : term ( (PLUS | MINUS) term )* + ; + +term + : factor ( (ASTERISK | DIV | MODULO) factor )* + ; + +factor + : literal + | functionCall + | variableAccess + | payloadAccess + | headerAccess + | configAccess + | attributeAccess + | LPAREN expression RPAREN + ; + +configAccess + : CONFIG DOT headerName + ; + +headerAccess + : HEADERS DOT headerName + ; + +headerName + : ID // Standard identifier + | STRING_LITERAL // Quoted string literal to allow spaces + ; + +attributeAccess + : ATTRIBUTES (DOT AXIS2 DOT propertyName // Access syntax for attributes.axis2.property + | DOT SYNAPSE DOT propertyName) // Access syntax for attributes.synapse.property + ; + +propertyName + : ID // Standard identifier + | STRING_LITERAL // Quoted string literal to allow spaces + ; + +literal + : arrayLiteral + | BOOLEAN_LITERAL + | NUMBER + | STRING_LITERAL + ; + +variableAccess + : VAR ( DOT ID // Dot notation: var.variableName + | (DOT)? LBRACKET STRING_LITERAL RBRACKET // Bracket notation: var["variableName"] + ) + ( (DOUBLE_DOT ASTERISK // Handles recursive descent and wildcard, like var.variableName..* + | DOT ASTERISK // Handles wildcard after dot notation, like var.variableName.* + | DOT ID + | LBRACKET arrayIndex RBRACKET // Handles array access, like var.variableName[...] + | DOT LBRACKET arrayIndex RBRACKET // Handles dot followed by bracket notation, like var.variableName.["property"] + )* + ) + ; + +arrayLiteral + : LBRACKET (expression (COMMA expression)*)? RBRACKET // Array with zero or more literals, separated by commas + ; + +payloadAccess + : PAYLOAD ( (DOUBLE_DOT ASTERISK + | DOUBLE_DOT ID + | DOT ID + | LBRACKET arrayIndex RBRACKET + | DOT LBRACKET arrayIndex RBRACKET + | DOT ASTERISK)* + | DOUBLE_DOT ID (LBRACKET arrayIndex RBRACKET)? ) + ; + +arrayIndex + : NUMBER + | STRING_LITERAL + | expression + | multipleArrayIndices + | sliceArrayIndex + | expression ( (PLUS | MINUS | MULT | DIV ) expression)* + | ASTERISK + | QUESTION filterExpression + ; + +multipleArrayIndices + : expression (COMMA expression)+ + ; + +sliceArrayIndex + : signedExpressions? COLON signedExpressions? (COLON signedExpressions?)? + ; + +signedExpressions + : MINUS? expression + ; + +filterExpression + : (filterComponent)+ + ; + +filterComponent + : variableAccess + | payloadAccess + | stringOrOperator + ; + +stringOrOperator + : QUESTION | AT | JSONPATH_FUNCTIONS| STRING_LITERAL |NUMBER | BOOLEAN_LITERAL | ID | GT | LT | GTE | LTE | EQ | NEQ + | PLUS | MINUS | MULT | DIV | LPAREN | RPAREN | DOT | COMMA | COLON | WS | AND | OR | NOT | ASTERISK + ; + +functionCall + : LENGTH LPAREN expression RPAREN + | TOUPPER LPAREN expression RPAREN + | TOLOWER LPAREN expression RPAREN + | SUBSTRING LPAREN expression COMMA expression (COMMA expression)? RPAREN + | STARTSWITH LPAREN expression COMMA expression RPAREN + | ENDSWITH LPAREN expression COMMA expression RPAREN + | CONTAINS LPAREN expression COMMA expression RPAREN + | TRIM LPAREN expression RPAREN + | REPLACE LPAREN expression COMMA expression COMMA expression RPAREN + | SPLIT LPAREN expression COMMA expression RPAREN + | ABS LPAREN expression RPAREN + | FLOOR LPAREN expression RPAREN + | CEIL LPAREN expression RPAREN + | SQRT LPAREN expression RPAREN + | LOG LPAREN expression RPAREN + | POW LPAREN expression COMMA expression RPAREN + | REGISTRY LPAREN expression RPAREN (DOT GETPROPERTY LPAREN expression RPAREN)? + | SECRET LPAREN expression RPAREN + | BASE64ENCODE LPAREN expression (COMMA expression)? RPAREN + | BASE64DECODE LPAREN expression RPAREN + | URLENCODE LPAREN expression (COMMA expression)? RPAREN + | URLDECODE LPAREN expression RPAREN + | ISNUMBER LPAREN expression RPAREN + | ISSTRING LPAREN expression RPAREN + | ISARRAY LPAREN expression RPAREN + | ISOBJECT LPAREN expression RPAREN + | NOW LPAREN RPAREN + | TODAY LPAREN STRING_LITERAL RPAREN + | FORMATDATE LPAREN expression COMMA STRING_LITERAL RPAREN + | ROUND LPAREN expression RPAREN + | INTEGER LPAREN expression RPAREN + | FLOAT LPAREN expression RPAREN + | STRING LPAREN expression RPAREN + | BOOLEAN LPAREN expression RPAREN + ; diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.interp b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.interp new file mode 100644 index 0000000000..b96e884757 --- /dev/null +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.interp @@ -0,0 +1,231 @@ +token literal names: +null +null +'var' +null +'headers' +'attributes' +'registry' +'secret' +'base64encode' +'base64decode' +'urlEncode' +'urlDecode' +'now' +'today' +'formatDate' +'isNumber' +'isString' +'isArray' +'isObject' +'round' +'integer' +'float' +'string' +'boolean' +'abs' +'floor' +'ceil' +'sqrt' +'log' +'pow' +'length' +'toUpper' +'toLower' +'subString' +'startsWith' +'endsWith' +'contains' +'trim' +'replace' +'split' +null +null +null +'..' +'*' +'+' +'-' +'/' +'%' +'==' +'!=' +'>' +'<' +'>=' +'<=' +'(' +')' +'[' +']' +'.' +',' +':' +null +null +null +null +null +'getProperty' +'?' +'@' +null + +token symbolic names: +null +JSONPATH_FUNCTIONS +VAR +PAYLOAD +HEADERS +ATTRIBUTES +REGISTRY +SECRET +BASE64ENCODE +BASE64DECODE +URLENCODE +URLDECODE +NOW +TODAY +FORMATDATE +ISNUMBER +ISSTRING +ISARRAY +ISOBJECT +ROUND +INTEGER +FLOAT +STRING +BOOLEAN +ABS +FLOOR +CEIL +SQRT +LOG +POW +LENGTH +TOUPPER +TOLOWER +SUBSTRING +STARTSWITH +ENDSWITH +CONTAINS +TRIM +REPLACE +SPLIT +AND +OR +NOT +DOUBLE_DOT +ASTERISK +PLUS +MINUS +DIV +MODULO +EQ +NEQ +GT +LT +GTE +LTE +LPAREN +RPAREN +LBRACKET +RBRACKET +DOT +COMMA +COLON +QUOTE +BOOLEAN_LITERAL +NUMBER +STRING_LITERAL +ID +GETPROPERTY +QUESTION +AT +WS + +rule names: +JSONPATH_FUNCTIONS +VAR +PAYLOAD +HEADERS +ATTRIBUTES +REGISTRY +SECRET +BASE64ENCODE +BASE64DECODE +URLENCODE +URLDECODE +NOW +TODAY +FORMATDATE +ISNUMBER +ISSTRING +ISARRAY +ISOBJECT +ROUND +INTEGER +FLOAT +STRING +BOOLEAN +ABS +FLOOR +CEIL +SQRT +LOG +POW +LENGTH +TOUPPER +TOLOWER +SUBSTRING +STARTSWITH +ENDSWITH +CONTAINS +TRIM +REPLACE +SPLIT +AND +OR +NOT +DOUBLE_DOT +ASTERISK +PLUS +MINUS +DIV +MODULO +EQ +NEQ +GT +LT +GTE +LTE +LPAREN +RPAREN +LBRACKET +RBRACKET +DOT +COMMA +COLON +QUOTE +BOOLEAN_LITERAL +NUMBER +STRING_LITERAL +ESC +UNICODE_ESC +OCTAL_ESC +HEX_DIGIT +ID +GETPROPERTY +QUESTION +AT +WS + +channel names: +DEFAULT_TOKEN_CHANNEL +HIDDEN + +mode names: +DEFAULT_MODE + +atn: +[4, 0, 70, 663, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 3, 0, 204, 8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 218, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 1, 26, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 31, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 35, 1, 36, 1, 36, 1, 36, 1, 36, 1, 36, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 38, 1, 39, 1, 39, 1, 39, 1, 39, 1, 39, 3, 39, 506, 8, 39, 1, 40, 1, 40, 1, 40, 1, 40, 3, 40, 512, 8, 40, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 518, 8, 41, 1, 42, 1, 42, 1, 42, 1, 43, 1, 43, 1, 44, 1, 44, 1, 45, 1, 45, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 56, 1, 56, 1, 57, 1, 57, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 3, 62, 574, 8, 62, 1, 63, 3, 63, 577, 8, 63, 1, 63, 4, 63, 580, 8, 63, 11, 63, 12, 63, 581, 1, 63, 1, 63, 4, 63, 586, 8, 63, 11, 63, 12, 63, 587, 3, 63, 590, 8, 63, 1, 64, 1, 64, 1, 64, 5, 64, 595, 8, 64, 10, 64, 12, 64, 598, 9, 64, 1, 64, 1, 64, 1, 64, 1, 64, 5, 64, 604, 8, 64, 10, 64, 12, 64, 607, 9, 64, 1, 64, 3, 64, 610, 8, 64, 1, 65, 1, 65, 1, 65, 1, 65, 3, 65, 616, 8, 65, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 3, 67, 627, 8, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 69, 1, 69, 5, 69, 636, 8, 69, 10, 69, 12, 69, 639, 9, 69, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 73, 4, 73, 658, 8, 73, 11, 73, 12, 73, 659, 1, 73, 1, 73, 0, 0, 74, 1, 1, 3, 2, 5, 3, 7, 4, 9, 5, 11, 6, 13, 7, 15, 8, 17, 9, 19, 10, 21, 11, 23, 12, 25, 13, 27, 14, 29, 15, 31, 16, 33, 17, 35, 18, 37, 19, 39, 20, 41, 21, 43, 22, 45, 23, 47, 24, 49, 25, 51, 26, 53, 27, 55, 28, 57, 29, 59, 30, 61, 31, 63, 32, 65, 33, 67, 34, 69, 35, 71, 36, 73, 37, 75, 38, 77, 39, 79, 40, 81, 41, 83, 42, 85, 43, 87, 44, 89, 45, 91, 46, 93, 47, 95, 48, 97, 49, 99, 50, 101, 51, 103, 52, 105, 53, 107, 54, 109, 55, 111, 56, 113, 57, 115, 58, 117, 59, 119, 60, 121, 61, 123, 62, 125, 63, 127, 64, 129, 65, 131, 0, 133, 0, 135, 0, 137, 0, 139, 66, 141, 67, 143, 68, 145, 69, 147, 70, 1, 0, 11, 2, 0, 34, 34, 39, 39, 1, 0, 48, 57, 2, 0, 34, 34, 92, 92, 2, 0, 39, 39, 92, 92, 9, 0, 34, 34, 39, 39, 47, 47, 92, 92, 98, 98, 102, 102, 110, 110, 114, 114, 116, 116, 1, 0, 48, 51, 1, 0, 48, 55, 3, 0, 48, 57, 65, 70, 97, 102, 3, 0, 65, 90, 95, 95, 97, 122, 4, 0, 48, 57, 65, 90, 95, 95, 97, 122, 3, 0, 9, 10, 13, 13, 32, 32, 685, 0, 1, 1, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, 9, 1, 0, 0, 0, 0, 11, 1, 0, 0, 0, 0, 13, 1, 0, 0, 0, 0, 15, 1, 0, 0, 0, 0, 17, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 0, 79, 1, 0, 0, 0, 0, 81, 1, 0, 0, 0, 0, 83, 1, 0, 0, 0, 0, 85, 1, 0, 0, 0, 0, 87, 1, 0, 0, 0, 0, 89, 1, 0, 0, 0, 0, 91, 1, 0, 0, 0, 0, 93, 1, 0, 0, 0, 0, 95, 1, 0, 0, 0, 0, 97, 1, 0, 0, 0, 0, 99, 1, 0, 0, 0, 0, 101, 1, 0, 0, 0, 0, 103, 1, 0, 0, 0, 0, 105, 1, 0, 0, 0, 0, 107, 1, 0, 0, 0, 0, 109, 1, 0, 0, 0, 0, 111, 1, 0, 0, 0, 0, 113, 1, 0, 0, 0, 0, 115, 1, 0, 0, 0, 0, 117, 1, 0, 0, 0, 0, 119, 1, 0, 0, 0, 0, 121, 1, 0, 0, 0, 0, 123, 1, 0, 0, 0, 0, 125, 1, 0, 0, 0, 0, 127, 1, 0, 0, 0, 0, 129, 1, 0, 0, 0, 0, 139, 1, 0, 0, 0, 0, 141, 1, 0, 0, 0, 0, 143, 1, 0, 0, 0, 0, 145, 1, 0, 0, 0, 0, 147, 1, 0, 0, 0, 1, 203, 1, 0, 0, 0, 3, 205, 1, 0, 0, 0, 5, 217, 1, 0, 0, 0, 7, 219, 1, 0, 0, 0, 9, 227, 1, 0, 0, 0, 11, 238, 1, 0, 0, 0, 13, 247, 1, 0, 0, 0, 15, 254, 1, 0, 0, 0, 17, 267, 1, 0, 0, 0, 19, 280, 1, 0, 0, 0, 21, 290, 1, 0, 0, 0, 23, 300, 1, 0, 0, 0, 25, 304, 1, 0, 0, 0, 27, 310, 1, 0, 0, 0, 29, 321, 1, 0, 0, 0, 31, 330, 1, 0, 0, 0, 33, 339, 1, 0, 0, 0, 35, 347, 1, 0, 0, 0, 37, 356, 1, 0, 0, 0, 39, 362, 1, 0, 0, 0, 41, 370, 1, 0, 0, 0, 43, 376, 1, 0, 0, 0, 45, 383, 1, 0, 0, 0, 47, 391, 1, 0, 0, 0, 49, 395, 1, 0, 0, 0, 51, 401, 1, 0, 0, 0, 53, 406, 1, 0, 0, 0, 55, 411, 1, 0, 0, 0, 57, 415, 1, 0, 0, 0, 59, 419, 1, 0, 0, 0, 61, 426, 1, 0, 0, 0, 63, 434, 1, 0, 0, 0, 65, 442, 1, 0, 0, 0, 67, 452, 1, 0, 0, 0, 69, 463, 1, 0, 0, 0, 71, 472, 1, 0, 0, 0, 73, 481, 1, 0, 0, 0, 75, 486, 1, 0, 0, 0, 77, 494, 1, 0, 0, 0, 79, 505, 1, 0, 0, 0, 81, 511, 1, 0, 0, 0, 83, 517, 1, 0, 0, 0, 85, 519, 1, 0, 0, 0, 87, 522, 1, 0, 0, 0, 89, 524, 1, 0, 0, 0, 91, 526, 1, 0, 0, 0, 93, 528, 1, 0, 0, 0, 95, 530, 1, 0, 0, 0, 97, 532, 1, 0, 0, 0, 99, 535, 1, 0, 0, 0, 101, 538, 1, 0, 0, 0, 103, 540, 1, 0, 0, 0, 105, 542, 1, 0, 0, 0, 107, 545, 1, 0, 0, 0, 109, 548, 1, 0, 0, 0, 111, 550, 1, 0, 0, 0, 113, 552, 1, 0, 0, 0, 115, 554, 1, 0, 0, 0, 117, 556, 1, 0, 0, 0, 119, 558, 1, 0, 0, 0, 121, 560, 1, 0, 0, 0, 123, 562, 1, 0, 0, 0, 125, 573, 1, 0, 0, 0, 127, 576, 1, 0, 0, 0, 129, 609, 1, 0, 0, 0, 131, 615, 1, 0, 0, 0, 133, 617, 1, 0, 0, 0, 135, 624, 1, 0, 0, 0, 137, 631, 1, 0, 0, 0, 139, 633, 1, 0, 0, 0, 141, 640, 1, 0, 0, 0, 143, 652, 1, 0, 0, 0, 145, 654, 1, 0, 0, 0, 147, 657, 1, 0, 0, 0, 149, 150, 5, 99, 0, 0, 150, 151, 5, 111, 0, 0, 151, 152, 5, 110, 0, 0, 152, 153, 5, 116, 0, 0, 153, 154, 5, 97, 0, 0, 154, 155, 5, 105, 0, 0, 155, 156, 5, 110, 0, 0, 156, 157, 5, 115, 0, 0, 157, 204, 5, 32, 0, 0, 158, 159, 5, 105, 0, 0, 159, 204, 5, 110, 0, 0, 160, 161, 5, 110, 0, 0, 161, 162, 5, 105, 0, 0, 162, 204, 5, 110, 0, 0, 163, 164, 5, 115, 0, 0, 164, 165, 5, 117, 0, 0, 165, 166, 5, 98, 0, 0, 166, 167, 5, 115, 0, 0, 167, 168, 5, 101, 0, 0, 168, 169, 5, 116, 0, 0, 169, 170, 5, 111, 0, 0, 170, 204, 5, 102, 0, 0, 171, 172, 5, 115, 0, 0, 172, 173, 5, 105, 0, 0, 173, 174, 5, 122, 0, 0, 174, 204, 5, 101, 0, 0, 175, 176, 5, 101, 0, 0, 176, 177, 5, 109, 0, 0, 177, 178, 5, 112, 0, 0, 178, 179, 5, 116, 0, 0, 179, 204, 5, 121, 0, 0, 180, 181, 5, 101, 0, 0, 181, 182, 5, 109, 0, 0, 182, 183, 5, 112, 0, 0, 183, 184, 5, 116, 0, 0, 184, 185, 5, 121, 0, 0, 185, 186, 5, 32, 0, 0, 186, 187, 5, 116, 0, 0, 187, 188, 5, 114, 0, 0, 188, 189, 5, 117, 0, 0, 189, 204, 5, 101, 0, 0, 190, 191, 5, 101, 0, 0, 191, 192, 5, 109, 0, 0, 192, 193, 5, 112, 0, 0, 193, 194, 5, 116, 0, 0, 194, 195, 5, 121, 0, 0, 195, 196, 5, 32, 0, 0, 196, 197, 5, 102, 0, 0, 197, 198, 5, 97, 0, 0, 198, 199, 5, 108, 0, 0, 199, 200, 5, 115, 0, 0, 200, 204, 5, 101, 0, 0, 201, 202, 5, 61, 0, 0, 202, 204, 5, 126, 0, 0, 203, 149, 1, 0, 0, 0, 203, 158, 1, 0, 0, 0, 203, 160, 1, 0, 0, 0, 203, 163, 1, 0, 0, 0, 203, 171, 1, 0, 0, 0, 203, 175, 1, 0, 0, 0, 203, 180, 1, 0, 0, 0, 203, 190, 1, 0, 0, 0, 203, 201, 1, 0, 0, 0, 204, 2, 1, 0, 0, 0, 205, 206, 5, 118, 0, 0, 206, 207, 5, 97, 0, 0, 207, 208, 5, 114, 0, 0, 208, 4, 1, 0, 0, 0, 209, 210, 5, 112, 0, 0, 210, 211, 5, 97, 0, 0, 211, 212, 5, 121, 0, 0, 212, 213, 5, 108, 0, 0, 213, 214, 5, 111, 0, 0, 214, 215, 5, 97, 0, 0, 215, 218, 5, 100, 0, 0, 216, 218, 5, 36, 0, 0, 217, 209, 1, 0, 0, 0, 217, 216, 1, 0, 0, 0, 218, 6, 1, 0, 0, 0, 219, 220, 5, 104, 0, 0, 220, 221, 5, 101, 0, 0, 221, 222, 5, 97, 0, 0, 222, 223, 5, 100, 0, 0, 223, 224, 5, 101, 0, 0, 224, 225, 5, 114, 0, 0, 225, 226, 5, 115, 0, 0, 226, 8, 1, 0, 0, 0, 227, 228, 5, 97, 0, 0, 228, 229, 5, 116, 0, 0, 229, 230, 5, 116, 0, 0, 230, 231, 5, 114, 0, 0, 231, 232, 5, 105, 0, 0, 232, 233, 5, 98, 0, 0, 233, 234, 5, 117, 0, 0, 234, 235, 5, 116, 0, 0, 235, 236, 5, 101, 0, 0, 236, 237, 5, 115, 0, 0, 237, 10, 1, 0, 0, 0, 238, 239, 5, 114, 0, 0, 239, 240, 5, 101, 0, 0, 240, 241, 5, 103, 0, 0, 241, 242, 5, 105, 0, 0, 242, 243, 5, 115, 0, 0, 243, 244, 5, 116, 0, 0, 244, 245, 5, 114, 0, 0, 245, 246, 5, 121, 0, 0, 246, 12, 1, 0, 0, 0, 247, 248, 5, 115, 0, 0, 248, 249, 5, 101, 0, 0, 249, 250, 5, 99, 0, 0, 250, 251, 5, 114, 0, 0, 251, 252, 5, 101, 0, 0, 252, 253, 5, 116, 0, 0, 253, 14, 1, 0, 0, 0, 254, 255, 5, 98, 0, 0, 255, 256, 5, 97, 0, 0, 256, 257, 5, 115, 0, 0, 257, 258, 5, 101, 0, 0, 258, 259, 5, 54, 0, 0, 259, 260, 5, 52, 0, 0, 260, 261, 5, 101, 0, 0, 261, 262, 5, 110, 0, 0, 262, 263, 5, 99, 0, 0, 263, 264, 5, 111, 0, 0, 264, 265, 5, 100, 0, 0, 265, 266, 5, 101, 0, 0, 266, 16, 1, 0, 0, 0, 267, 268, 5, 98, 0, 0, 268, 269, 5, 97, 0, 0, 269, 270, 5, 115, 0, 0, 270, 271, 5, 101, 0, 0, 271, 272, 5, 54, 0, 0, 272, 273, 5, 52, 0, 0, 273, 274, 5, 100, 0, 0, 274, 275, 5, 101, 0, 0, 275, 276, 5, 99, 0, 0, 276, 277, 5, 111, 0, 0, 277, 278, 5, 100, 0, 0, 278, 279, 5, 101, 0, 0, 279, 18, 1, 0, 0, 0, 280, 281, 5, 117, 0, 0, 281, 282, 5, 114, 0, 0, 282, 283, 5, 108, 0, 0, 283, 284, 5, 69, 0, 0, 284, 285, 5, 110, 0, 0, 285, 286, 5, 99, 0, 0, 286, 287, 5, 111, 0, 0, 287, 288, 5, 100, 0, 0, 288, 289, 5, 101, 0, 0, 289, 20, 1, 0, 0, 0, 290, 291, 5, 117, 0, 0, 291, 292, 5, 114, 0, 0, 292, 293, 5, 108, 0, 0, 293, 294, 5, 68, 0, 0, 294, 295, 5, 101, 0, 0, 295, 296, 5, 99, 0, 0, 296, 297, 5, 111, 0, 0, 297, 298, 5, 100, 0, 0, 298, 299, 5, 101, 0, 0, 299, 22, 1, 0, 0, 0, 300, 301, 5, 110, 0, 0, 301, 302, 5, 111, 0, 0, 302, 303, 5, 119, 0, 0, 303, 24, 1, 0, 0, 0, 304, 305, 5, 116, 0, 0, 305, 306, 5, 111, 0, 0, 306, 307, 5, 100, 0, 0, 307, 308, 5, 97, 0, 0, 308, 309, 5, 121, 0, 0, 309, 26, 1, 0, 0, 0, 310, 311, 5, 102, 0, 0, 311, 312, 5, 111, 0, 0, 312, 313, 5, 114, 0, 0, 313, 314, 5, 109, 0, 0, 314, 315, 5, 97, 0, 0, 315, 316, 5, 116, 0, 0, 316, 317, 5, 68, 0, 0, 317, 318, 5, 97, 0, 0, 318, 319, 5, 116, 0, 0, 319, 320, 5, 101, 0, 0, 320, 28, 1, 0, 0, 0, 321, 322, 5, 105, 0, 0, 322, 323, 5, 115, 0, 0, 323, 324, 5, 78, 0, 0, 324, 325, 5, 117, 0, 0, 325, 326, 5, 109, 0, 0, 326, 327, 5, 98, 0, 0, 327, 328, 5, 101, 0, 0, 328, 329, 5, 114, 0, 0, 329, 30, 1, 0, 0, 0, 330, 331, 5, 105, 0, 0, 331, 332, 5, 115, 0, 0, 332, 333, 5, 83, 0, 0, 333, 334, 5, 116, 0, 0, 334, 335, 5, 114, 0, 0, 335, 336, 5, 105, 0, 0, 336, 337, 5, 110, 0, 0, 337, 338, 5, 103, 0, 0, 338, 32, 1, 0, 0, 0, 339, 340, 5, 105, 0, 0, 340, 341, 5, 115, 0, 0, 341, 342, 5, 65, 0, 0, 342, 343, 5, 114, 0, 0, 343, 344, 5, 114, 0, 0, 344, 345, 5, 97, 0, 0, 345, 346, 5, 121, 0, 0, 346, 34, 1, 0, 0, 0, 347, 348, 5, 105, 0, 0, 348, 349, 5, 115, 0, 0, 349, 350, 5, 79, 0, 0, 350, 351, 5, 98, 0, 0, 351, 352, 5, 106, 0, 0, 352, 353, 5, 101, 0, 0, 353, 354, 5, 99, 0, 0, 354, 355, 5, 116, 0, 0, 355, 36, 1, 0, 0, 0, 356, 357, 5, 114, 0, 0, 357, 358, 5, 111, 0, 0, 358, 359, 5, 117, 0, 0, 359, 360, 5, 110, 0, 0, 360, 361, 5, 100, 0, 0, 361, 38, 1, 0, 0, 0, 362, 363, 5, 105, 0, 0, 363, 364, 5, 110, 0, 0, 364, 365, 5, 116, 0, 0, 365, 366, 5, 101, 0, 0, 366, 367, 5, 103, 0, 0, 367, 368, 5, 101, 0, 0, 368, 369, 5, 114, 0, 0, 369, 40, 1, 0, 0, 0, 370, 371, 5, 102, 0, 0, 371, 372, 5, 108, 0, 0, 372, 373, 5, 111, 0, 0, 373, 374, 5, 97, 0, 0, 374, 375, 5, 116, 0, 0, 375, 42, 1, 0, 0, 0, 376, 377, 5, 115, 0, 0, 377, 378, 5, 116, 0, 0, 378, 379, 5, 114, 0, 0, 379, 380, 5, 105, 0, 0, 380, 381, 5, 110, 0, 0, 381, 382, 5, 103, 0, 0, 382, 44, 1, 0, 0, 0, 383, 384, 5, 98, 0, 0, 384, 385, 5, 111, 0, 0, 385, 386, 5, 111, 0, 0, 386, 387, 5, 108, 0, 0, 387, 388, 5, 101, 0, 0, 388, 389, 5, 97, 0, 0, 389, 390, 5, 110, 0, 0, 390, 46, 1, 0, 0, 0, 391, 392, 5, 97, 0, 0, 392, 393, 5, 98, 0, 0, 393, 394, 5, 115, 0, 0, 394, 48, 1, 0, 0, 0, 395, 396, 5, 102, 0, 0, 396, 397, 5, 108, 0, 0, 397, 398, 5, 111, 0, 0, 398, 399, 5, 111, 0, 0, 399, 400, 5, 114, 0, 0, 400, 50, 1, 0, 0, 0, 401, 402, 5, 99, 0, 0, 402, 403, 5, 101, 0, 0, 403, 404, 5, 105, 0, 0, 404, 405, 5, 108, 0, 0, 405, 52, 1, 0, 0, 0, 406, 407, 5, 115, 0, 0, 407, 408, 5, 113, 0, 0, 408, 409, 5, 114, 0, 0, 409, 410, 5, 116, 0, 0, 410, 54, 1, 0, 0, 0, 411, 412, 5, 108, 0, 0, 412, 413, 5, 111, 0, 0, 413, 414, 5, 103, 0, 0, 414, 56, 1, 0, 0, 0, 415, 416, 5, 112, 0, 0, 416, 417, 5, 111, 0, 0, 417, 418, 5, 119, 0, 0, 418, 58, 1, 0, 0, 0, 419, 420, 5, 108, 0, 0, 420, 421, 5, 101, 0, 0, 421, 422, 5, 110, 0, 0, 422, 423, 5, 103, 0, 0, 423, 424, 5, 116, 0, 0, 424, 425, 5, 104, 0, 0, 425, 60, 1, 0, 0, 0, 426, 427, 5, 116, 0, 0, 427, 428, 5, 111, 0, 0, 428, 429, 5, 85, 0, 0, 429, 430, 5, 112, 0, 0, 430, 431, 5, 112, 0, 0, 431, 432, 5, 101, 0, 0, 432, 433, 5, 114, 0, 0, 433, 62, 1, 0, 0, 0, 434, 435, 5, 116, 0, 0, 435, 436, 5, 111, 0, 0, 436, 437, 5, 76, 0, 0, 437, 438, 5, 111, 0, 0, 438, 439, 5, 119, 0, 0, 439, 440, 5, 101, 0, 0, 440, 441, 5, 114, 0, 0, 441, 64, 1, 0, 0, 0, 442, 443, 5, 115, 0, 0, 443, 444, 5, 117, 0, 0, 444, 445, 5, 98, 0, 0, 445, 446, 5, 83, 0, 0, 446, 447, 5, 116, 0, 0, 447, 448, 5, 114, 0, 0, 448, 449, 5, 105, 0, 0, 449, 450, 5, 110, 0, 0, 450, 451, 5, 103, 0, 0, 451, 66, 1, 0, 0, 0, 452, 453, 5, 115, 0, 0, 453, 454, 5, 116, 0, 0, 454, 455, 5, 97, 0, 0, 455, 456, 5, 114, 0, 0, 456, 457, 5, 116, 0, 0, 457, 458, 5, 115, 0, 0, 458, 459, 5, 87, 0, 0, 459, 460, 5, 105, 0, 0, 460, 461, 5, 116, 0, 0, 461, 462, 5, 104, 0, 0, 462, 68, 1, 0, 0, 0, 463, 464, 5, 101, 0, 0, 464, 465, 5, 110, 0, 0, 465, 466, 5, 100, 0, 0, 466, 467, 5, 115, 0, 0, 467, 468, 5, 87, 0, 0, 468, 469, 5, 105, 0, 0, 469, 470, 5, 116, 0, 0, 470, 471, 5, 104, 0, 0, 471, 70, 1, 0, 0, 0, 472, 473, 5, 99, 0, 0, 473, 474, 5, 111, 0, 0, 474, 475, 5, 110, 0, 0, 475, 476, 5, 116, 0, 0, 476, 477, 5, 97, 0, 0, 477, 478, 5, 105, 0, 0, 478, 479, 5, 110, 0, 0, 479, 480, 5, 115, 0, 0, 480, 72, 1, 0, 0, 0, 481, 482, 5, 116, 0, 0, 482, 483, 5, 114, 0, 0, 483, 484, 5, 105, 0, 0, 484, 485, 5, 109, 0, 0, 485, 74, 1, 0, 0, 0, 486, 487, 5, 114, 0, 0, 487, 488, 5, 101, 0, 0, 488, 489, 5, 112, 0, 0, 489, 490, 5, 108, 0, 0, 490, 491, 5, 97, 0, 0, 491, 492, 5, 99, 0, 0, 492, 493, 5, 101, 0, 0, 493, 76, 1, 0, 0, 0, 494, 495, 5, 115, 0, 0, 495, 496, 5, 112, 0, 0, 496, 497, 5, 108, 0, 0, 497, 498, 5, 105, 0, 0, 498, 499, 5, 116, 0, 0, 499, 78, 1, 0, 0, 0, 500, 501, 5, 97, 0, 0, 501, 502, 5, 110, 0, 0, 502, 506, 5, 100, 0, 0, 503, 504, 5, 38, 0, 0, 504, 506, 5, 38, 0, 0, 505, 500, 1, 0, 0, 0, 505, 503, 1, 0, 0, 0, 506, 80, 1, 0, 0, 0, 507, 508, 5, 111, 0, 0, 508, 512, 5, 114, 0, 0, 509, 510, 5, 124, 0, 0, 510, 512, 5, 124, 0, 0, 511, 507, 1, 0, 0, 0, 511, 509, 1, 0, 0, 0, 512, 82, 1, 0, 0, 0, 513, 514, 5, 110, 0, 0, 514, 515, 5, 111, 0, 0, 515, 518, 5, 116, 0, 0, 516, 518, 5, 33, 0, 0, 517, 513, 1, 0, 0, 0, 517, 516, 1, 0, 0, 0, 518, 84, 1, 0, 0, 0, 519, 520, 5, 46, 0, 0, 520, 521, 5, 46, 0, 0, 521, 86, 1, 0, 0, 0, 522, 523, 5, 42, 0, 0, 523, 88, 1, 0, 0, 0, 524, 525, 5, 43, 0, 0, 525, 90, 1, 0, 0, 0, 526, 527, 5, 45, 0, 0, 527, 92, 1, 0, 0, 0, 528, 529, 5, 47, 0, 0, 529, 94, 1, 0, 0, 0, 530, 531, 5, 37, 0, 0, 531, 96, 1, 0, 0, 0, 532, 533, 5, 61, 0, 0, 533, 534, 5, 61, 0, 0, 534, 98, 1, 0, 0, 0, 535, 536, 5, 33, 0, 0, 536, 537, 5, 61, 0, 0, 537, 100, 1, 0, 0, 0, 538, 539, 5, 62, 0, 0, 539, 102, 1, 0, 0, 0, 540, 541, 5, 60, 0, 0, 541, 104, 1, 0, 0, 0, 542, 543, 5, 62, 0, 0, 543, 544, 5, 61, 0, 0, 544, 106, 1, 0, 0, 0, 545, 546, 5, 60, 0, 0, 546, 547, 5, 61, 0, 0, 547, 108, 1, 0, 0, 0, 548, 549, 5, 40, 0, 0, 549, 110, 1, 0, 0, 0, 550, 551, 5, 41, 0, 0, 551, 112, 1, 0, 0, 0, 552, 553, 5, 91, 0, 0, 553, 114, 1, 0, 0, 0, 554, 555, 5, 93, 0, 0, 555, 116, 1, 0, 0, 0, 556, 557, 5, 46, 0, 0, 557, 118, 1, 0, 0, 0, 558, 559, 5, 44, 0, 0, 559, 120, 1, 0, 0, 0, 560, 561, 5, 58, 0, 0, 561, 122, 1, 0, 0, 0, 562, 563, 7, 0, 0, 0, 563, 124, 1, 0, 0, 0, 564, 565, 5, 116, 0, 0, 565, 566, 5, 114, 0, 0, 566, 567, 5, 117, 0, 0, 567, 574, 5, 101, 0, 0, 568, 569, 5, 102, 0, 0, 569, 570, 5, 97, 0, 0, 570, 571, 5, 108, 0, 0, 571, 572, 5, 115, 0, 0, 572, 574, 5, 101, 0, 0, 573, 564, 1, 0, 0, 0, 573, 568, 1, 0, 0, 0, 574, 126, 1, 0, 0, 0, 575, 577, 5, 45, 0, 0, 576, 575, 1, 0, 0, 0, 576, 577, 1, 0, 0, 0, 577, 579, 1, 0, 0, 0, 578, 580, 7, 1, 0, 0, 579, 578, 1, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 579, 1, 0, 0, 0, 581, 582, 1, 0, 0, 0, 582, 589, 1, 0, 0, 0, 583, 585, 5, 46, 0, 0, 584, 586, 7, 1, 0, 0, 585, 584, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 585, 1, 0, 0, 0, 587, 588, 1, 0, 0, 0, 588, 590, 1, 0, 0, 0, 589, 583, 1, 0, 0, 0, 589, 590, 1, 0, 0, 0, 590, 128, 1, 0, 0, 0, 591, 596, 5, 34, 0, 0, 592, 595, 3, 131, 65, 0, 593, 595, 8, 2, 0, 0, 594, 592, 1, 0, 0, 0, 594, 593, 1, 0, 0, 0, 595, 598, 1, 0, 0, 0, 596, 594, 1, 0, 0, 0, 596, 597, 1, 0, 0, 0, 597, 599, 1, 0, 0, 0, 598, 596, 1, 0, 0, 0, 599, 610, 5, 34, 0, 0, 600, 605, 5, 39, 0, 0, 601, 604, 3, 131, 65, 0, 602, 604, 8, 3, 0, 0, 603, 601, 1, 0, 0, 0, 603, 602, 1, 0, 0, 0, 604, 607, 1, 0, 0, 0, 605, 603, 1, 0, 0, 0, 605, 606, 1, 0, 0, 0, 606, 608, 1, 0, 0, 0, 607, 605, 1, 0, 0, 0, 608, 610, 5, 39, 0, 0, 609, 591, 1, 0, 0, 0, 609, 600, 1, 0, 0, 0, 610, 130, 1, 0, 0, 0, 611, 612, 5, 92, 0, 0, 612, 616, 7, 4, 0, 0, 613, 616, 3, 133, 66, 0, 614, 616, 3, 135, 67, 0, 615, 611, 1, 0, 0, 0, 615, 613, 1, 0, 0, 0, 615, 614, 1, 0, 0, 0, 616, 132, 1, 0, 0, 0, 617, 618, 5, 92, 0, 0, 618, 619, 5, 117, 0, 0, 619, 620, 3, 137, 68, 0, 620, 621, 3, 137, 68, 0, 621, 622, 3, 137, 68, 0, 622, 623, 3, 137, 68, 0, 623, 134, 1, 0, 0, 0, 624, 626, 5, 92, 0, 0, 625, 627, 7, 5, 0, 0, 626, 625, 1, 0, 0, 0, 626, 627, 1, 0, 0, 0, 627, 628, 1, 0, 0, 0, 628, 629, 7, 6, 0, 0, 629, 630, 7, 6, 0, 0, 630, 136, 1, 0, 0, 0, 631, 632, 7, 7, 0, 0, 632, 138, 1, 0, 0, 0, 633, 637, 7, 8, 0, 0, 634, 636, 7, 9, 0, 0, 635, 634, 1, 0, 0, 0, 636, 639, 1, 0, 0, 0, 637, 635, 1, 0, 0, 0, 637, 638, 1, 0, 0, 0, 638, 140, 1, 0, 0, 0, 639, 637, 1, 0, 0, 0, 640, 641, 5, 103, 0, 0, 641, 642, 5, 101, 0, 0, 642, 643, 5, 116, 0, 0, 643, 644, 5, 80, 0, 0, 644, 645, 5, 114, 0, 0, 645, 646, 5, 111, 0, 0, 646, 647, 5, 112, 0, 0, 647, 648, 5, 101, 0, 0, 648, 649, 5, 114, 0, 0, 649, 650, 5, 116, 0, 0, 650, 651, 5, 121, 0, 0, 651, 142, 1, 0, 0, 0, 652, 653, 5, 63, 0, 0, 653, 144, 1, 0, 0, 0, 654, 655, 5, 64, 0, 0, 655, 146, 1, 0, 0, 0, 656, 658, 7, 10, 0, 0, 657, 656, 1, 0, 0, 0, 658, 659, 1, 0, 0, 0, 659, 657, 1, 0, 0, 0, 659, 660, 1, 0, 0, 0, 660, 661, 1, 0, 0, 0, 661, 662, 6, 73, 0, 0, 662, 148, 1, 0, 0, 0, 20, 0, 203, 217, 505, 511, 517, 573, 576, 581, 587, 589, 594, 596, 603, 605, 609, 615, 626, 637, 659, 1, 6, 0, 0] \ No newline at end of file diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.java b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.java new file mode 100644 index 0000000000..cacaa9cf81 --- /dev/null +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.java @@ -0,0 +1,554 @@ +// Generated from /Users/lahirumadushanka/Documents/repo/wso2-synapse/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/ExpressionLexer.g4 by ANTLR 4.13.2 +import org.antlr.v4.runtime.Lexer; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.TokenStream; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.atn.*; +import org.antlr.v4.runtime.dfa.DFA; +import org.antlr.v4.runtime.misc.*; + +@SuppressWarnings({"all", "warnings", "unchecked", "unused", "cast", "CheckReturnValue", "this-escape"}) +public class ExpressionLexer extends Lexer { + static { RuntimeMetaData.checkVersion("4.13.2", RuntimeMetaData.VERSION); } + + protected static final DFA[] _decisionToDFA; + protected static final PredictionContextCache _sharedContextCache = + new PredictionContextCache(); + public static final int + JSONPATH_FUNCTIONS=1, VAR=2, PAYLOAD=3, HEADERS=4, ATTRIBUTES=5, REGISTRY=6, + SECRET=7, BASE64ENCODE=8, BASE64DECODE=9, URLENCODE=10, URLDECODE=11, + NOW=12, TODAY=13, FORMATDATE=14, ISNUMBER=15, ISSTRING=16, ISARRAY=17, + ISOBJECT=18, ROUND=19, INTEGER=20, FLOAT=21, STRING=22, BOOLEAN=23, ABS=24, + FLOOR=25, CEIL=26, SQRT=27, LOG=28, POW=29, LENGTH=30, TOUPPER=31, TOLOWER=32, + SUBSTRING=33, STARTSWITH=34, ENDSWITH=35, CONTAINS=36, TRIM=37, REPLACE=38, + SPLIT=39, AND=40, OR=41, NOT=42, DOUBLE_DOT=43, ASTERISK=44, PLUS=45, + MINUS=46, DIV=47, MODULO=48, EQ=49, NEQ=50, GT=51, LT=52, GTE=53, LTE=54, + LPAREN=55, RPAREN=56, LBRACKET=57, RBRACKET=58, DOT=59, COMMA=60, COLON=61, + QUOTE=62, BOOLEAN_LITERAL=63, NUMBER=64, STRING_LITERAL=65, ID=66, GETPROPERTY=67, + QUESTION=68, AT=69, WS=70; + public static String[] channelNames = { + "DEFAULT_TOKEN_CHANNEL", "HIDDEN" + }; + + public static String[] modeNames = { + "DEFAULT_MODE" + }; + + private static String[] makeRuleNames() { + return new String[] { + "JSONPATH_FUNCTIONS", "VAR", "PAYLOAD", "HEADERS", "ATTRIBUTES", "REGISTRY", + "SECRET", "BASE64ENCODE", "BASE64DECODE", "URLENCODE", "URLDECODE", "NOW", + "TODAY", "FORMATDATE", "ISNUMBER", "ISSTRING", "ISARRAY", "ISOBJECT", + "ROUND", "INTEGER", "FLOAT", "STRING", "BOOLEAN", "ABS", "FLOOR", "CEIL", + "SQRT", "LOG", "POW", "LENGTH", "TOUPPER", "TOLOWER", "SUBSTRING", "STARTSWITH", + "ENDSWITH", "CONTAINS", "TRIM", "REPLACE", "SPLIT", "AND", "OR", "NOT", + "DOUBLE_DOT", "ASTERISK", "PLUS", "MINUS", "DIV", "MODULO", "EQ", "NEQ", + "GT", "LT", "GTE", "LTE", "LPAREN", "RPAREN", "LBRACKET", "RBRACKET", + "DOT", "COMMA", "COLON", "QUOTE", "BOOLEAN_LITERAL", "NUMBER", "STRING_LITERAL", + "ESC", "UNICODE_ESC", "OCTAL_ESC", "HEX_DIGIT", "ID", "GETPROPERTY", + "QUESTION", "AT", "WS" + }; + } + public static final String[] ruleNames = makeRuleNames(); + + private static String[] makeLiteralNames() { + return new String[] { + null, null, "'var'", null, "'headers'", "'attributes'", "'registry'", + "'secret'", "'base64encode'", "'base64decode'", "'urlEncode'", "'urlDecode'", + "'now'", "'today'", "'formatDate'", "'isNumber'", "'isString'", "'isArray'", + "'isObject'", "'round'", "'integer'", "'float'", "'string'", "'boolean'", + "'abs'", "'floor'", "'ceil'", "'sqrt'", "'log'", "'pow'", "'length'", + "'toUpper'", "'toLower'", "'subString'", "'startsWith'", "'endsWith'", + "'contains'", "'trim'", "'replace'", "'split'", null, null, null, "'..'", + "'*'", "'+'", "'-'", "'/'", "'%'", "'=='", "'!='", "'>'", "'<'", "'>='", + "'<='", "'('", "')'", "'['", "']'", "'.'", "','", "':'", null, null, + null, null, null, "'getProperty'", "'?'", "'@'" + }; + } + private static final String[] _LITERAL_NAMES = makeLiteralNames(); + private static String[] makeSymbolicNames() { + return new String[] { + null, "JSONPATH_FUNCTIONS", "VAR", "PAYLOAD", "HEADERS", "ATTRIBUTES", + "REGISTRY", "SECRET", "BASE64ENCODE", "BASE64DECODE", "URLENCODE", "URLDECODE", + "NOW", "TODAY", "FORMATDATE", "ISNUMBER", "ISSTRING", "ISARRAY", "ISOBJECT", + "ROUND", "INTEGER", "FLOAT", "STRING", "BOOLEAN", "ABS", "FLOOR", "CEIL", + "SQRT", "LOG", "POW", "LENGTH", "TOUPPER", "TOLOWER", "SUBSTRING", "STARTSWITH", + "ENDSWITH", "CONTAINS", "TRIM", "REPLACE", "SPLIT", "AND", "OR", "NOT", + "DOUBLE_DOT", "ASTERISK", "PLUS", "MINUS", "DIV", "MODULO", "EQ", "NEQ", + "GT", "LT", "GTE", "LTE", "LPAREN", "RPAREN", "LBRACKET", "RBRACKET", + "DOT", "COMMA", "COLON", "QUOTE", "BOOLEAN_LITERAL", "NUMBER", "STRING_LITERAL", + "ID", "GETPROPERTY", "QUESTION", "AT", "WS" + }; + } + private static final String[] _SYMBOLIC_NAMES = makeSymbolicNames(); + public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES); + + /** + * @deprecated Use {@link #VOCABULARY} instead. + */ + @Deprecated + public static final String[] tokenNames; + static { + tokenNames = new String[_SYMBOLIC_NAMES.length]; + for (int i = 0; i < tokenNames.length; i++) { + tokenNames[i] = VOCABULARY.getLiteralName(i); + if (tokenNames[i] == null) { + tokenNames[i] = VOCABULARY.getSymbolicName(i); + } + + if (tokenNames[i] == null) { + tokenNames[i] = ""; + } + } + } + + @Override + @Deprecated + public String[] getTokenNames() { + return tokenNames; + } + + @Override + + public Vocabulary getVocabulary() { + return VOCABULARY; + } + + + public ExpressionLexer(CharStream input) { + super(input); + _interp = new LexerATNSimulator(this,_ATN,_decisionToDFA,_sharedContextCache); + } + + @Override + public String getGrammarFileName() { return "ExpressionLexer.g4"; } + + @Override + public String[] getRuleNames() { return ruleNames; } + + @Override + public String getSerializedATN() { return _serializedATN; } + + @Override + public String[] getChannelNames() { return channelNames; } + + @Override + public String[] getModeNames() { return modeNames; } + + @Override + public ATN getATN() { return _ATN; } + + public static final String _serializedATN = + "\u0004\u0000F\u0297\u0006\uffff\uffff\u0002\u0000\u0007\u0000\u0002\u0001"+ + "\u0007\u0001\u0002\u0002\u0007\u0002\u0002\u0003\u0007\u0003\u0002\u0004"+ + "\u0007\u0004\u0002\u0005\u0007\u0005\u0002\u0006\u0007\u0006\u0002\u0007"+ + "\u0007\u0007\u0002\b\u0007\b\u0002\t\u0007\t\u0002\n\u0007\n\u0002\u000b"+ + "\u0007\u000b\u0002\f\u0007\f\u0002\r\u0007\r\u0002\u000e\u0007\u000e\u0002"+ + "\u000f\u0007\u000f\u0002\u0010\u0007\u0010\u0002\u0011\u0007\u0011\u0002"+ + "\u0012\u0007\u0012\u0002\u0013\u0007\u0013\u0002\u0014\u0007\u0014\u0002"+ + "\u0015\u0007\u0015\u0002\u0016\u0007\u0016\u0002\u0017\u0007\u0017\u0002"+ + "\u0018\u0007\u0018\u0002\u0019\u0007\u0019\u0002\u001a\u0007\u001a\u0002"+ + "\u001b\u0007\u001b\u0002\u001c\u0007\u001c\u0002\u001d\u0007\u001d\u0002"+ + "\u001e\u0007\u001e\u0002\u001f\u0007\u001f\u0002 \u0007 \u0002!\u0007"+ + "!\u0002\"\u0007\"\u0002#\u0007#\u0002$\u0007$\u0002%\u0007%\u0002&\u0007"+ + "&\u0002\'\u0007\'\u0002(\u0007(\u0002)\u0007)\u0002*\u0007*\u0002+\u0007"+ + "+\u0002,\u0007,\u0002-\u0007-\u0002.\u0007.\u0002/\u0007/\u00020\u0007"+ + "0\u00021\u00071\u00022\u00072\u00023\u00073\u00024\u00074\u00025\u0007"+ + "5\u00026\u00076\u00027\u00077\u00028\u00078\u00029\u00079\u0002:\u0007"+ + ":\u0002;\u0007;\u0002<\u0007<\u0002=\u0007=\u0002>\u0007>\u0002?\u0007"+ + "?\u0002@\u0007@\u0002A\u0007A\u0002B\u0007B\u0002C\u0007C\u0002D\u0007"+ + "D\u0002E\u0007E\u0002F\u0007F\u0002G\u0007G\u0002H\u0007H\u0002I\u0007"+ + "I\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ + "\u0003\u0000\u00cc\b\u0000\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001"+ + "\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002\u0001\u0002"+ + "\u0001\u0002\u0001\u0002\u0003\u0002\u00da\b\u0002\u0001\u0003\u0001\u0003"+ + "\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003\u0001\u0003"+ + "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004"+ + "\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0004\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005\u0001\u0005"+ + "\u0001\u0005\u0001\u0005\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0006"+ + "\u0001\u0006\u0001\u0006\u0001\u0006\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007"+ + "\u0001\u0007\u0001\u0007\u0001\u0007\u0001\u0007\u0001\b\u0001\b\u0001"+ + "\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001\b\u0001"+ + "\b\u0001\b\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001\t\u0001"+ + "\t\u0001\t\u0001\t\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001\n\u0001"+ + "\n\u0001\n\u0001\n\u0001\n\u0001\u000b\u0001\u000b\u0001\u000b\u0001\u000b"+ + "\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\f\u0001\r\u0001\r\u0001"+ + "\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001\r\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001\u000e\u0001"+ + "\u000e\u0001\u000e\u0001\u000e\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ + "\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001\u000f\u0001"+ + "\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001\u0010\u0001"+ + "\u0010\u0001\u0010\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001"+ + "\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0011\u0001\u0012\u0001"+ + "\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0012\u0001\u0013\u0001"+ + "\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001\u0013\u0001"+ + "\u0013\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001\u0014\u0001"+ + "\u0014\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001\u0015\u0001"+ + "\u0015\u0001\u0015\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001"+ + "\u0016\u0001\u0016\u0001\u0016\u0001\u0016\u0001\u0017\u0001\u0017\u0001"+ + "\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001"+ + "\u0018\u0001\u0018\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001"+ + "\u0019\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001\u001a\u0001"+ + "\u001b\u0001\u001b\u0001\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001"+ + "\u001c\u0001\u001c\u0001\u001d\u0001\u001d\u0001\u001d\u0001\u001d\u0001"+ + "\u001d\u0001\u001d\u0001\u001d\u0001\u001e\u0001\u001e\u0001\u001e\u0001"+ + "\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001"+ + "\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001\u001f\u0001"+ + "\u001f\u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 \u0001 "+ + "\u0001 \u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001!\u0001"+ + "!\u0001!\u0001!\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001\"\u0001"+ + "\"\u0001\"\u0001\"\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001#\u0001"+ + "#\u0001#\u0001$\u0001$\u0001$\u0001$\u0001$\u0001%\u0001%\u0001%\u0001"+ + "%\u0001%\u0001%\u0001%\u0001%\u0001&\u0001&\u0001&\u0001&\u0001&\u0001"+ + "&\u0001\'\u0001\'\u0001\'\u0001\'\u0001\'\u0003\'\u01fa\b\'\u0001(\u0001"+ + "(\u0001(\u0001(\u0003(\u0200\b(\u0001)\u0001)\u0001)\u0001)\u0003)\u0206"+ + "\b)\u0001*\u0001*\u0001*\u0001+\u0001+\u0001,\u0001,\u0001-\u0001-\u0001"+ + ".\u0001.\u0001/\u0001/\u00010\u00010\u00010\u00011\u00011\u00011\u0001"+ + "2\u00012\u00013\u00013\u00014\u00014\u00014\u00015\u00015\u00015\u0001"+ + "6\u00016\u00017\u00017\u00018\u00018\u00019\u00019\u0001:\u0001:\u0001"+ + ";\u0001;\u0001<\u0001<\u0001=\u0001=\u0001>\u0001>\u0001>\u0001>\u0001"+ + ">\u0001>\u0001>\u0001>\u0001>\u0003>\u023e\b>\u0001?\u0003?\u0241\b?\u0001"+ + "?\u0004?\u0244\b?\u000b?\f?\u0245\u0001?\u0001?\u0004?\u024a\b?\u000b"+ + "?\f?\u024b\u0003?\u024e\b?\u0001@\u0001@\u0001@\u0005@\u0253\b@\n@\f@"+ + "\u0256\t@\u0001@\u0001@\u0001@\u0001@\u0005@\u025c\b@\n@\f@\u025f\t@\u0001"+ + "@\u0003@\u0262\b@\u0001A\u0001A\u0001A\u0001A\u0003A\u0268\bA\u0001B\u0001"+ + "B\u0001B\u0001B\u0001B\u0001B\u0001B\u0001C\u0001C\u0003C\u0273\bC\u0001"+ + "C\u0001C\u0001C\u0001D\u0001D\u0001E\u0001E\u0005E\u027c\bE\nE\fE\u027f"+ + "\tE\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001F\u0001"+ + "F\u0001F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001I\u0004I\u0292\bI\u000b"+ + "I\fI\u0293\u0001I\u0001I\u0000\u0000J\u0001\u0001\u0003\u0002\u0005\u0003"+ + "\u0007\u0004\t\u0005\u000b\u0006\r\u0007\u000f\b\u0011\t\u0013\n\u0015"+ + "\u000b\u0017\f\u0019\r\u001b\u000e\u001d\u000f\u001f\u0010!\u0011#\u0012"+ + "%\u0013\'\u0014)\u0015+\u0016-\u0017/\u00181\u00193\u001a5\u001b7\u001c"+ + "9\u001d;\u001e=\u001f? A!C\"E#G$I%K&M\'O(Q)S*U+W,Y-[.]/_0a1c2e3g4i5k6"+ + "m7o8q9s:u;w}?\u007f@\u0081A\u0083\u0000\u0085\u0000\u0087\u0000\u0089"+ + "\u0000\u008bB\u008dC\u008fD\u0091E\u0093F\u0001\u0000\u000b\u0002\u0000"+ + "\"\"\'\'\u0001\u000009\u0002\u0000\"\"\\\\\u0002\u0000\'\'\\\\\t\u0000"+ + "\"\"\'\'//\\\\bbffnnrrtt\u0001\u000003\u0001\u000007\u0003\u000009AFa"+ + "f\u0003\u0000AZ__az\u0004\u000009AZ__az\u0003\u0000\t\n\r\r \u02ad\u0000"+ + "\u0001\u0001\u0000\u0000\u0000\u0000\u0003\u0001\u0000\u0000\u0000\u0000"+ + "\u0005\u0001\u0000\u0000\u0000\u0000\u0007\u0001\u0000\u0000\u0000\u0000"+ + "\t\u0001\u0000\u0000\u0000\u0000\u000b\u0001\u0000\u0000\u0000\u0000\r"+ + "\u0001\u0000\u0000\u0000\u0000\u000f\u0001\u0000\u0000\u0000\u0000\u0011"+ + "\u0001\u0000\u0000\u0000\u0000\u0013\u0001\u0000\u0000\u0000\u0000\u0015"+ + "\u0001\u0000\u0000\u0000\u0000\u0017\u0001\u0000\u0000\u0000\u0000\u0019"+ + "\u0001\u0000\u0000\u0000\u0000\u001b\u0001\u0000\u0000\u0000\u0000\u001d"+ + "\u0001\u0000\u0000\u0000\u0000\u001f\u0001\u0000\u0000\u0000\u0000!\u0001"+ + "\u0000\u0000\u0000\u0000#\u0001\u0000\u0000\u0000\u0000%\u0001\u0000\u0000"+ + "\u0000\u0000\'\u0001\u0000\u0000\u0000\u0000)\u0001\u0000\u0000\u0000"+ + "\u0000+\u0001\u0000\u0000\u0000\u0000-\u0001\u0000\u0000\u0000\u0000/"+ + "\u0001\u0000\u0000\u0000\u00001\u0001\u0000\u0000\u0000\u00003\u0001\u0000"+ + "\u0000\u0000\u00005\u0001\u0000\u0000\u0000\u00007\u0001\u0000\u0000\u0000"+ + "\u00009\u0001\u0000\u0000\u0000\u0000;\u0001\u0000\u0000\u0000\u0000="+ + "\u0001\u0000\u0000\u0000\u0000?\u0001\u0000\u0000\u0000\u0000A\u0001\u0000"+ + "\u0000\u0000\u0000C\u0001\u0000\u0000\u0000\u0000E\u0001\u0000\u0000\u0000"+ + "\u0000G\u0001\u0000\u0000\u0000\u0000I\u0001\u0000\u0000\u0000\u0000K"+ + "\u0001\u0000\u0000\u0000\u0000M\u0001\u0000\u0000\u0000\u0000O\u0001\u0000"+ + "\u0000\u0000\u0000Q\u0001\u0000\u0000\u0000\u0000S\u0001\u0000\u0000\u0000"+ + "\u0000U\u0001\u0000\u0000\u0000\u0000W\u0001\u0000\u0000\u0000\u0000Y"+ + "\u0001\u0000\u0000\u0000\u0000[\u0001\u0000\u0000\u0000\u0000]\u0001\u0000"+ + "\u0000\u0000\u0000_\u0001\u0000\u0000\u0000\u0000a\u0001\u0000\u0000\u0000"+ + "\u0000c\u0001\u0000\u0000\u0000\u0000e\u0001\u0000\u0000\u0000\u0000g"+ + "\u0001\u0000\u0000\u0000\u0000i\u0001\u0000\u0000\u0000\u0000k\u0001\u0000"+ + "\u0000\u0000\u0000m\u0001\u0000\u0000\u0000\u0000o\u0001\u0000\u0000\u0000"+ + "\u0000q\u0001\u0000\u0000\u0000\u0000s\u0001\u0000\u0000\u0000\u0000u"+ + "\u0001\u0000\u0000\u0000\u0000w\u0001\u0000\u0000\u0000\u0000y\u0001\u0000"+ + "\u0000\u0000\u0000{\u0001\u0000\u0000\u0000\u0000}\u0001\u0000\u0000\u0000"+ + "\u0000\u007f\u0001\u0000\u0000\u0000\u0000\u0081\u0001\u0000\u0000\u0000"+ + "\u0000\u008b\u0001\u0000\u0000\u0000\u0000\u008d\u0001\u0000\u0000\u0000"+ + "\u0000\u008f\u0001\u0000\u0000\u0000\u0000\u0091\u0001\u0000\u0000\u0000"+ + "\u0000\u0093\u0001\u0000\u0000\u0000\u0001\u00cb\u0001\u0000\u0000\u0000"+ + "\u0003\u00cd\u0001\u0000\u0000\u0000\u0005\u00d9\u0001\u0000\u0000\u0000"+ + "\u0007\u00db\u0001\u0000\u0000\u0000\t\u00e3\u0001\u0000\u0000\u0000\u000b"+ + "\u00ee\u0001\u0000\u0000\u0000\r\u00f7\u0001\u0000\u0000\u0000\u000f\u00fe"+ + "\u0001\u0000\u0000\u0000\u0011\u010b\u0001\u0000\u0000\u0000\u0013\u0118"+ + "\u0001\u0000\u0000\u0000\u0015\u0122\u0001\u0000\u0000\u0000\u0017\u012c"+ + "\u0001\u0000\u0000\u0000\u0019\u0130\u0001\u0000\u0000\u0000\u001b\u0136"+ + "\u0001\u0000\u0000\u0000\u001d\u0141\u0001\u0000\u0000\u0000\u001f\u014a"+ + "\u0001\u0000\u0000\u0000!\u0153\u0001\u0000\u0000\u0000#\u015b\u0001\u0000"+ + "\u0000\u0000%\u0164\u0001\u0000\u0000\u0000\'\u016a\u0001\u0000\u0000"+ + "\u0000)\u0172\u0001\u0000\u0000\u0000+\u0178\u0001\u0000\u0000\u0000-"+ + "\u017f\u0001\u0000\u0000\u0000/\u0187\u0001\u0000\u0000\u00001\u018b\u0001"+ + "\u0000\u0000\u00003\u0191\u0001\u0000\u0000\u00005\u0196\u0001\u0000\u0000"+ + "\u00007\u019b\u0001\u0000\u0000\u00009\u019f\u0001\u0000\u0000\u0000;"+ + "\u01a3\u0001\u0000\u0000\u0000=\u01aa\u0001\u0000\u0000\u0000?\u01b2\u0001"+ + "\u0000\u0000\u0000A\u01ba\u0001\u0000\u0000\u0000C\u01c4\u0001\u0000\u0000"+ + "\u0000E\u01cf\u0001\u0000\u0000\u0000G\u01d8\u0001\u0000\u0000\u0000I"+ + "\u01e1\u0001\u0000\u0000\u0000K\u01e6\u0001\u0000\u0000\u0000M\u01ee\u0001"+ + "\u0000\u0000\u0000O\u01f9\u0001\u0000\u0000\u0000Q\u01ff\u0001\u0000\u0000"+ + "\u0000S\u0205\u0001\u0000\u0000\u0000U\u0207\u0001\u0000\u0000\u0000W"+ + "\u020a\u0001\u0000\u0000\u0000Y\u020c\u0001\u0000\u0000\u0000[\u020e\u0001"+ + "\u0000\u0000\u0000]\u0210\u0001\u0000\u0000\u0000_\u0212\u0001\u0000\u0000"+ + "\u0000a\u0214\u0001\u0000\u0000\u0000c\u0217\u0001\u0000\u0000\u0000e"+ + "\u021a\u0001\u0000\u0000\u0000g\u021c\u0001\u0000\u0000\u0000i\u021e\u0001"+ + "\u0000\u0000\u0000k\u0221\u0001\u0000\u0000\u0000m\u0224\u0001\u0000\u0000"+ + "\u0000o\u0226\u0001\u0000\u0000\u0000q\u0228\u0001\u0000\u0000\u0000s"+ + "\u022a\u0001\u0000\u0000\u0000u\u022c\u0001\u0000\u0000\u0000w\u022e\u0001"+ + "\u0000\u0000\u0000y\u0230\u0001\u0000\u0000\u0000{\u0232\u0001\u0000\u0000"+ + "\u0000}\u023d\u0001\u0000\u0000\u0000\u007f\u0240\u0001\u0000\u0000\u0000"+ + "\u0081\u0261\u0001\u0000\u0000\u0000\u0083\u0267\u0001\u0000\u0000\u0000"+ + "\u0085\u0269\u0001\u0000\u0000\u0000\u0087\u0270\u0001\u0000\u0000\u0000"+ + "\u0089\u0277\u0001\u0000\u0000\u0000\u008b\u0279\u0001\u0000\u0000\u0000"+ + "\u008d\u0280\u0001\u0000\u0000\u0000\u008f\u028c\u0001\u0000\u0000\u0000"+ + "\u0091\u028e\u0001\u0000\u0000\u0000\u0093\u0291\u0001\u0000\u0000\u0000"+ + "\u0095\u0096\u0005c\u0000\u0000\u0096\u0097\u0005o\u0000\u0000\u0097\u0098"+ + "\u0005n\u0000\u0000\u0098\u0099\u0005t\u0000\u0000\u0099\u009a\u0005a"+ + "\u0000\u0000\u009a\u009b\u0005i\u0000\u0000\u009b\u009c\u0005n\u0000\u0000"+ + "\u009c\u009d\u0005s\u0000\u0000\u009d\u00cc\u0005 \u0000\u0000\u009e\u009f"+ + "\u0005i\u0000\u0000\u009f\u00cc\u0005n\u0000\u0000\u00a0\u00a1\u0005n"+ + "\u0000\u0000\u00a1\u00a2\u0005i\u0000\u0000\u00a2\u00cc\u0005n\u0000\u0000"+ + "\u00a3\u00a4\u0005s\u0000\u0000\u00a4\u00a5\u0005u\u0000\u0000\u00a5\u00a6"+ + "\u0005b\u0000\u0000\u00a6\u00a7\u0005s\u0000\u0000\u00a7\u00a8\u0005e"+ + "\u0000\u0000\u00a8\u00a9\u0005t\u0000\u0000\u00a9\u00aa\u0005o\u0000\u0000"+ + "\u00aa\u00cc\u0005f\u0000\u0000\u00ab\u00ac\u0005s\u0000\u0000\u00ac\u00ad"+ + "\u0005i\u0000\u0000\u00ad\u00ae\u0005z\u0000\u0000\u00ae\u00cc\u0005e"+ + "\u0000\u0000\u00af\u00b0\u0005e\u0000\u0000\u00b0\u00b1\u0005m\u0000\u0000"+ + "\u00b1\u00b2\u0005p\u0000\u0000\u00b2\u00b3\u0005t\u0000\u0000\u00b3\u00cc"+ + "\u0005y\u0000\u0000\u00b4\u00b5\u0005e\u0000\u0000\u00b5\u00b6\u0005m"+ + "\u0000\u0000\u00b6\u00b7\u0005p\u0000\u0000\u00b7\u00b8\u0005t\u0000\u0000"+ + "\u00b8\u00b9\u0005y\u0000\u0000\u00b9\u00ba\u0005 \u0000\u0000\u00ba\u00bb"+ + "\u0005t\u0000\u0000\u00bb\u00bc\u0005r\u0000\u0000\u00bc\u00bd\u0005u"+ + "\u0000\u0000\u00bd\u00cc\u0005e\u0000\u0000\u00be\u00bf\u0005e\u0000\u0000"+ + "\u00bf\u00c0\u0005m\u0000\u0000\u00c0\u00c1\u0005p\u0000\u0000\u00c1\u00c2"+ + "\u0005t\u0000\u0000\u00c2\u00c3\u0005y\u0000\u0000\u00c3\u00c4\u0005 "+ + "\u0000\u0000\u00c4\u00c5\u0005f\u0000\u0000\u00c5\u00c6\u0005a\u0000\u0000"+ + "\u00c6\u00c7\u0005l\u0000\u0000\u00c7\u00c8\u0005s\u0000\u0000\u00c8\u00cc"+ + "\u0005e\u0000\u0000\u00c9\u00ca\u0005=\u0000\u0000\u00ca\u00cc\u0005~"+ + "\u0000\u0000\u00cb\u0095\u0001\u0000\u0000\u0000\u00cb\u009e\u0001\u0000"+ + "\u0000\u0000\u00cb\u00a0\u0001\u0000\u0000\u0000\u00cb\u00a3\u0001\u0000"+ + "\u0000\u0000\u00cb\u00ab\u0001\u0000\u0000\u0000\u00cb\u00af\u0001\u0000"+ + "\u0000\u0000\u00cb\u00b4\u0001\u0000\u0000\u0000\u00cb\u00be\u0001\u0000"+ + "\u0000\u0000\u00cb\u00c9\u0001\u0000\u0000\u0000\u00cc\u0002\u0001\u0000"+ + "\u0000\u0000\u00cd\u00ce\u0005v\u0000\u0000\u00ce\u00cf\u0005a\u0000\u0000"+ + "\u00cf\u00d0\u0005r\u0000\u0000\u00d0\u0004\u0001\u0000\u0000\u0000\u00d1"+ + "\u00d2\u0005p\u0000\u0000\u00d2\u00d3\u0005a\u0000\u0000\u00d3\u00d4\u0005"+ + "y\u0000\u0000\u00d4\u00d5\u0005l\u0000\u0000\u00d5\u00d6\u0005o\u0000"+ + "\u0000\u00d6\u00d7\u0005a\u0000\u0000\u00d7\u00da\u0005d\u0000\u0000\u00d8"+ + "\u00da\u0005$\u0000\u0000\u00d9\u00d1\u0001\u0000\u0000\u0000\u00d9\u00d8"+ + "\u0001\u0000\u0000\u0000\u00da\u0006\u0001\u0000\u0000\u0000\u00db\u00dc"+ + "\u0005h\u0000\u0000\u00dc\u00dd\u0005e\u0000\u0000\u00dd\u00de\u0005a"+ + "\u0000\u0000\u00de\u00df\u0005d\u0000\u0000\u00df\u00e0\u0005e\u0000\u0000"+ + "\u00e0\u00e1\u0005r\u0000\u0000\u00e1\u00e2\u0005s\u0000\u0000\u00e2\b"+ + "\u0001\u0000\u0000\u0000\u00e3\u00e4\u0005a\u0000\u0000\u00e4\u00e5\u0005"+ + "t\u0000\u0000\u00e5\u00e6\u0005t\u0000\u0000\u00e6\u00e7\u0005r\u0000"+ + "\u0000\u00e7\u00e8\u0005i\u0000\u0000\u00e8\u00e9\u0005b\u0000\u0000\u00e9"+ + "\u00ea\u0005u\u0000\u0000\u00ea\u00eb\u0005t\u0000\u0000\u00eb\u00ec\u0005"+ + "e\u0000\u0000\u00ec\u00ed\u0005s\u0000\u0000\u00ed\n\u0001\u0000\u0000"+ + "\u0000\u00ee\u00ef\u0005r\u0000\u0000\u00ef\u00f0\u0005e\u0000\u0000\u00f0"+ + "\u00f1\u0005g\u0000\u0000\u00f1\u00f2\u0005i\u0000\u0000\u00f2\u00f3\u0005"+ + "s\u0000\u0000\u00f3\u00f4\u0005t\u0000\u0000\u00f4\u00f5\u0005r\u0000"+ + "\u0000\u00f5\u00f6\u0005y\u0000\u0000\u00f6\f\u0001\u0000\u0000\u0000"+ + "\u00f7\u00f8\u0005s\u0000\u0000\u00f8\u00f9\u0005e\u0000\u0000\u00f9\u00fa"+ + "\u0005c\u0000\u0000\u00fa\u00fb\u0005r\u0000\u0000\u00fb\u00fc\u0005e"+ + "\u0000\u0000\u00fc\u00fd\u0005t\u0000\u0000\u00fd\u000e\u0001\u0000\u0000"+ + "\u0000\u00fe\u00ff\u0005b\u0000\u0000\u00ff\u0100\u0005a\u0000\u0000\u0100"+ + "\u0101\u0005s\u0000\u0000\u0101\u0102\u0005e\u0000\u0000\u0102\u0103\u0005"+ + "6\u0000\u0000\u0103\u0104\u00054\u0000\u0000\u0104\u0105\u0005e\u0000"+ + "\u0000\u0105\u0106\u0005n\u0000\u0000\u0106\u0107\u0005c\u0000\u0000\u0107"+ + "\u0108\u0005o\u0000\u0000\u0108\u0109\u0005d\u0000\u0000\u0109\u010a\u0005"+ + "e\u0000\u0000\u010a\u0010\u0001\u0000\u0000\u0000\u010b\u010c\u0005b\u0000"+ + "\u0000\u010c\u010d\u0005a\u0000\u0000\u010d\u010e\u0005s\u0000\u0000\u010e"+ + "\u010f\u0005e\u0000\u0000\u010f\u0110\u00056\u0000\u0000\u0110\u0111\u0005"+ + "4\u0000\u0000\u0111\u0112\u0005d\u0000\u0000\u0112\u0113\u0005e\u0000"+ + "\u0000\u0113\u0114\u0005c\u0000\u0000\u0114\u0115\u0005o\u0000\u0000\u0115"+ + "\u0116\u0005d\u0000\u0000\u0116\u0117\u0005e\u0000\u0000\u0117\u0012\u0001"+ + "\u0000\u0000\u0000\u0118\u0119\u0005u\u0000\u0000\u0119\u011a\u0005r\u0000"+ + "\u0000\u011a\u011b\u0005l\u0000\u0000\u011b\u011c\u0005E\u0000\u0000\u011c"+ + "\u011d\u0005n\u0000\u0000\u011d\u011e\u0005c\u0000\u0000\u011e\u011f\u0005"+ + "o\u0000\u0000\u011f\u0120\u0005d\u0000\u0000\u0120\u0121\u0005e\u0000"+ + "\u0000\u0121\u0014\u0001\u0000\u0000\u0000\u0122\u0123\u0005u\u0000\u0000"+ + "\u0123\u0124\u0005r\u0000\u0000\u0124\u0125\u0005l\u0000\u0000\u0125\u0126"+ + "\u0005D\u0000\u0000\u0126\u0127\u0005e\u0000\u0000\u0127\u0128\u0005c"+ + "\u0000\u0000\u0128\u0129\u0005o\u0000\u0000\u0129\u012a\u0005d\u0000\u0000"+ + "\u012a\u012b\u0005e\u0000\u0000\u012b\u0016\u0001\u0000\u0000\u0000\u012c"+ + "\u012d\u0005n\u0000\u0000\u012d\u012e\u0005o\u0000\u0000\u012e\u012f\u0005"+ + "w\u0000\u0000\u012f\u0018\u0001\u0000\u0000\u0000\u0130\u0131\u0005t\u0000"+ + "\u0000\u0131\u0132\u0005o\u0000\u0000\u0132\u0133\u0005d\u0000\u0000\u0133"+ + "\u0134\u0005a\u0000\u0000\u0134\u0135\u0005y\u0000\u0000\u0135\u001a\u0001"+ + "\u0000\u0000\u0000\u0136\u0137\u0005f\u0000\u0000\u0137\u0138\u0005o\u0000"+ + "\u0000\u0138\u0139\u0005r\u0000\u0000\u0139\u013a\u0005m\u0000\u0000\u013a"+ + "\u013b\u0005a\u0000\u0000\u013b\u013c\u0005t\u0000\u0000\u013c\u013d\u0005"+ + "D\u0000\u0000\u013d\u013e\u0005a\u0000\u0000\u013e\u013f\u0005t\u0000"+ + "\u0000\u013f\u0140\u0005e\u0000\u0000\u0140\u001c\u0001\u0000\u0000\u0000"+ + "\u0141\u0142\u0005i\u0000\u0000\u0142\u0143\u0005s\u0000\u0000\u0143\u0144"+ + "\u0005N\u0000\u0000\u0144\u0145\u0005u\u0000\u0000\u0145\u0146\u0005m"+ + "\u0000\u0000\u0146\u0147\u0005b\u0000\u0000\u0147\u0148\u0005e\u0000\u0000"+ + "\u0148\u0149\u0005r\u0000\u0000\u0149\u001e\u0001\u0000\u0000\u0000\u014a"+ + "\u014b\u0005i\u0000\u0000\u014b\u014c\u0005s\u0000\u0000\u014c\u014d\u0005"+ + "S\u0000\u0000\u014d\u014e\u0005t\u0000\u0000\u014e\u014f\u0005r\u0000"+ + "\u0000\u014f\u0150\u0005i\u0000\u0000\u0150\u0151\u0005n\u0000\u0000\u0151"+ + "\u0152\u0005g\u0000\u0000\u0152 \u0001\u0000\u0000\u0000\u0153\u0154\u0005"+ + "i\u0000\u0000\u0154\u0155\u0005s\u0000\u0000\u0155\u0156\u0005A\u0000"+ + "\u0000\u0156\u0157\u0005r\u0000\u0000\u0157\u0158\u0005r\u0000\u0000\u0158"+ + "\u0159\u0005a\u0000\u0000\u0159\u015a\u0005y\u0000\u0000\u015a\"\u0001"+ + "\u0000\u0000\u0000\u015b\u015c\u0005i\u0000\u0000\u015c\u015d\u0005s\u0000"+ + "\u0000\u015d\u015e\u0005O\u0000\u0000\u015e\u015f\u0005b\u0000\u0000\u015f"+ + "\u0160\u0005j\u0000\u0000\u0160\u0161\u0005e\u0000\u0000\u0161\u0162\u0005"+ + "c\u0000\u0000\u0162\u0163\u0005t\u0000\u0000\u0163$\u0001\u0000\u0000"+ + "\u0000\u0164\u0165\u0005r\u0000\u0000\u0165\u0166\u0005o\u0000\u0000\u0166"+ + "\u0167\u0005u\u0000\u0000\u0167\u0168\u0005n\u0000\u0000\u0168\u0169\u0005"+ + "d\u0000\u0000\u0169&\u0001\u0000\u0000\u0000\u016a\u016b\u0005i\u0000"+ + "\u0000\u016b\u016c\u0005n\u0000\u0000\u016c\u016d\u0005t\u0000\u0000\u016d"+ + "\u016e\u0005e\u0000\u0000\u016e\u016f\u0005g\u0000\u0000\u016f\u0170\u0005"+ + "e\u0000\u0000\u0170\u0171\u0005r\u0000\u0000\u0171(\u0001\u0000\u0000"+ + "\u0000\u0172\u0173\u0005f\u0000\u0000\u0173\u0174\u0005l\u0000\u0000\u0174"+ + "\u0175\u0005o\u0000\u0000\u0175\u0176\u0005a\u0000\u0000\u0176\u0177\u0005"+ + "t\u0000\u0000\u0177*\u0001\u0000\u0000\u0000\u0178\u0179\u0005s\u0000"+ + "\u0000\u0179\u017a\u0005t\u0000\u0000\u017a\u017b\u0005r\u0000\u0000\u017b"+ + "\u017c\u0005i\u0000\u0000\u017c\u017d\u0005n\u0000\u0000\u017d\u017e\u0005"+ + "g\u0000\u0000\u017e,\u0001\u0000\u0000\u0000\u017f\u0180\u0005b\u0000"+ + "\u0000\u0180\u0181\u0005o\u0000\u0000\u0181\u0182\u0005o\u0000\u0000\u0182"+ + "\u0183\u0005l\u0000\u0000\u0183\u0184\u0005e\u0000\u0000\u0184\u0185\u0005"+ + "a\u0000\u0000\u0185\u0186\u0005n\u0000\u0000\u0186.\u0001\u0000\u0000"+ + "\u0000\u0187\u0188\u0005a\u0000\u0000\u0188\u0189\u0005b\u0000\u0000\u0189"+ + "\u018a\u0005s\u0000\u0000\u018a0\u0001\u0000\u0000\u0000\u018b\u018c\u0005"+ + "f\u0000\u0000\u018c\u018d\u0005l\u0000\u0000\u018d\u018e\u0005o\u0000"+ + "\u0000\u018e\u018f\u0005o\u0000\u0000\u018f\u0190\u0005r\u0000\u0000\u0190"+ + "2\u0001\u0000\u0000\u0000\u0191\u0192\u0005c\u0000\u0000\u0192\u0193\u0005"+ + "e\u0000\u0000\u0193\u0194\u0005i\u0000\u0000\u0194\u0195\u0005l\u0000"+ + "\u0000\u01954\u0001\u0000\u0000\u0000\u0196\u0197\u0005s\u0000\u0000\u0197"+ + "\u0198\u0005q\u0000\u0000\u0198\u0199\u0005r\u0000\u0000\u0199\u019a\u0005"+ + "t\u0000\u0000\u019a6\u0001\u0000\u0000\u0000\u019b\u019c\u0005l\u0000"+ + "\u0000\u019c\u019d\u0005o\u0000\u0000\u019d\u019e\u0005g\u0000\u0000\u019e"+ + "8\u0001\u0000\u0000\u0000\u019f\u01a0\u0005p\u0000\u0000\u01a0\u01a1\u0005"+ + "o\u0000\u0000\u01a1\u01a2\u0005w\u0000\u0000\u01a2:\u0001\u0000\u0000"+ + "\u0000\u01a3\u01a4\u0005l\u0000\u0000\u01a4\u01a5\u0005e\u0000\u0000\u01a5"+ + "\u01a6\u0005n\u0000\u0000\u01a6\u01a7\u0005g\u0000\u0000\u01a7\u01a8\u0005"+ + "t\u0000\u0000\u01a8\u01a9\u0005h\u0000\u0000\u01a9<\u0001\u0000\u0000"+ + "\u0000\u01aa\u01ab\u0005t\u0000\u0000\u01ab\u01ac\u0005o\u0000\u0000\u01ac"+ + "\u01ad\u0005U\u0000\u0000\u01ad\u01ae\u0005p\u0000\u0000\u01ae\u01af\u0005"+ + "p\u0000\u0000\u01af\u01b0\u0005e\u0000\u0000\u01b0\u01b1\u0005r\u0000"+ + "\u0000\u01b1>\u0001\u0000\u0000\u0000\u01b2\u01b3\u0005t\u0000\u0000\u01b3"+ + "\u01b4\u0005o\u0000\u0000\u01b4\u01b5\u0005L\u0000\u0000\u01b5\u01b6\u0005"+ + "o\u0000\u0000\u01b6\u01b7\u0005w\u0000\u0000\u01b7\u01b8\u0005e\u0000"+ + "\u0000\u01b8\u01b9\u0005r\u0000\u0000\u01b9@\u0001\u0000\u0000\u0000\u01ba"+ + "\u01bb\u0005s\u0000\u0000\u01bb\u01bc\u0005u\u0000\u0000\u01bc\u01bd\u0005"+ + "b\u0000\u0000\u01bd\u01be\u0005S\u0000\u0000\u01be\u01bf\u0005t\u0000"+ + "\u0000\u01bf\u01c0\u0005r\u0000\u0000\u01c0\u01c1\u0005i\u0000\u0000\u01c1"+ + "\u01c2\u0005n\u0000\u0000\u01c2\u01c3\u0005g\u0000\u0000\u01c3B\u0001"+ + "\u0000\u0000\u0000\u01c4\u01c5\u0005s\u0000\u0000\u01c5\u01c6\u0005t\u0000"+ + "\u0000\u01c6\u01c7\u0005a\u0000\u0000\u01c7\u01c8\u0005r\u0000\u0000\u01c8"+ + "\u01c9\u0005t\u0000\u0000\u01c9\u01ca\u0005s\u0000\u0000\u01ca\u01cb\u0005"+ + "W\u0000\u0000\u01cb\u01cc\u0005i\u0000\u0000\u01cc\u01cd\u0005t\u0000"+ + "\u0000\u01cd\u01ce\u0005h\u0000\u0000\u01ceD\u0001\u0000\u0000\u0000\u01cf"+ + "\u01d0\u0005e\u0000\u0000\u01d0\u01d1\u0005n\u0000\u0000\u01d1\u01d2\u0005"+ + "d\u0000\u0000\u01d2\u01d3\u0005s\u0000\u0000\u01d3\u01d4\u0005W\u0000"+ + "\u0000\u01d4\u01d5\u0005i\u0000\u0000\u01d5\u01d6\u0005t\u0000\u0000\u01d6"+ + "\u01d7\u0005h\u0000\u0000\u01d7F\u0001\u0000\u0000\u0000\u01d8\u01d9\u0005"+ + "c\u0000\u0000\u01d9\u01da\u0005o\u0000\u0000\u01da\u01db\u0005n\u0000"+ + "\u0000\u01db\u01dc\u0005t\u0000\u0000\u01dc\u01dd\u0005a\u0000\u0000\u01dd"+ + "\u01de\u0005i\u0000\u0000\u01de\u01df\u0005n\u0000\u0000\u01df\u01e0\u0005"+ + "s\u0000\u0000\u01e0H\u0001\u0000\u0000\u0000\u01e1\u01e2\u0005t\u0000"+ + "\u0000\u01e2\u01e3\u0005r\u0000\u0000\u01e3\u01e4\u0005i\u0000\u0000\u01e4"+ + "\u01e5\u0005m\u0000\u0000\u01e5J\u0001\u0000\u0000\u0000\u01e6\u01e7\u0005"+ + "r\u0000\u0000\u01e7\u01e8\u0005e\u0000\u0000\u01e8\u01e9\u0005p\u0000"+ + "\u0000\u01e9\u01ea\u0005l\u0000\u0000\u01ea\u01eb\u0005a\u0000\u0000\u01eb"+ + "\u01ec\u0005c\u0000\u0000\u01ec\u01ed\u0005e\u0000\u0000\u01edL\u0001"+ + "\u0000\u0000\u0000\u01ee\u01ef\u0005s\u0000\u0000\u01ef\u01f0\u0005p\u0000"+ + "\u0000\u01f0\u01f1\u0005l\u0000\u0000\u01f1\u01f2\u0005i\u0000\u0000\u01f2"+ + "\u01f3\u0005t\u0000\u0000\u01f3N\u0001\u0000\u0000\u0000\u01f4\u01f5\u0005"+ + "a\u0000\u0000\u01f5\u01f6\u0005n\u0000\u0000\u01f6\u01fa\u0005d\u0000"+ + "\u0000\u01f7\u01f8\u0005&\u0000\u0000\u01f8\u01fa\u0005&\u0000\u0000\u01f9"+ + "\u01f4\u0001\u0000\u0000\u0000\u01f9\u01f7\u0001\u0000\u0000\u0000\u01fa"+ + "P\u0001\u0000\u0000\u0000\u01fb\u01fc\u0005o\u0000\u0000\u01fc\u0200\u0005"+ + "r\u0000\u0000\u01fd\u01fe\u0005|\u0000\u0000\u01fe\u0200\u0005|\u0000"+ + "\u0000\u01ff\u01fb\u0001\u0000\u0000\u0000\u01ff\u01fd\u0001\u0000\u0000"+ + "\u0000\u0200R\u0001\u0000\u0000\u0000\u0201\u0202\u0005n\u0000\u0000\u0202"+ + "\u0203\u0005o\u0000\u0000\u0203\u0206\u0005t\u0000\u0000\u0204\u0206\u0005"+ + "!\u0000\u0000\u0205\u0201\u0001\u0000\u0000\u0000\u0205\u0204\u0001\u0000"+ + "\u0000\u0000\u0206T\u0001\u0000\u0000\u0000\u0207\u0208\u0005.\u0000\u0000"+ + "\u0208\u0209\u0005.\u0000\u0000\u0209V\u0001\u0000\u0000\u0000\u020a\u020b"+ + "\u0005*\u0000\u0000\u020bX\u0001\u0000\u0000\u0000\u020c\u020d\u0005+"+ + "\u0000\u0000\u020dZ\u0001\u0000\u0000\u0000\u020e\u020f\u0005-\u0000\u0000"+ + "\u020f\\\u0001\u0000\u0000\u0000\u0210\u0211\u0005/\u0000\u0000\u0211"+ + "^\u0001\u0000\u0000\u0000\u0212\u0213\u0005%\u0000\u0000\u0213`\u0001"+ + "\u0000\u0000\u0000\u0214\u0215\u0005=\u0000\u0000\u0215\u0216\u0005=\u0000"+ + "\u0000\u0216b\u0001\u0000\u0000\u0000\u0217\u0218\u0005!\u0000\u0000\u0218"+ + "\u0219\u0005=\u0000\u0000\u0219d\u0001\u0000\u0000\u0000\u021a\u021b\u0005"+ + ">\u0000\u0000\u021bf\u0001\u0000\u0000\u0000\u021c\u021d\u0005<\u0000"+ + "\u0000\u021dh\u0001\u0000\u0000\u0000\u021e\u021f\u0005>\u0000\u0000\u021f"+ + "\u0220\u0005=\u0000\u0000\u0220j\u0001\u0000\u0000\u0000\u0221\u0222\u0005"+ + "<\u0000\u0000\u0222\u0223\u0005=\u0000\u0000\u0223l\u0001\u0000\u0000"+ + "\u0000\u0224\u0225\u0005(\u0000\u0000\u0225n\u0001\u0000\u0000\u0000\u0226"+ + "\u0227\u0005)\u0000\u0000\u0227p\u0001\u0000\u0000\u0000\u0228\u0229\u0005"+ + "[\u0000\u0000\u0229r\u0001\u0000\u0000\u0000\u022a\u022b\u0005]\u0000"+ + "\u0000\u022bt\u0001\u0000\u0000\u0000\u022c\u022d\u0005.\u0000\u0000\u022d"+ + "v\u0001\u0000\u0000\u0000\u022e\u022f\u0005,\u0000\u0000\u022fx\u0001"+ + "\u0000\u0000\u0000\u0230\u0231\u0005:\u0000\u0000\u0231z\u0001\u0000\u0000"+ + "\u0000\u0232\u0233\u0007\u0000\u0000\u0000\u0233|\u0001\u0000\u0000\u0000"+ + "\u0234\u0235\u0005t\u0000\u0000\u0235\u0236\u0005r\u0000\u0000\u0236\u0237"+ + "\u0005u\u0000\u0000\u0237\u023e\u0005e\u0000\u0000\u0238\u0239\u0005f"+ + "\u0000\u0000\u0239\u023a\u0005a\u0000\u0000\u023a\u023b\u0005l\u0000\u0000"+ + "\u023b\u023c\u0005s\u0000\u0000\u023c\u023e\u0005e\u0000\u0000\u023d\u0234"+ + "\u0001\u0000\u0000\u0000\u023d\u0238\u0001\u0000\u0000\u0000\u023e~\u0001"+ + "\u0000\u0000\u0000\u023f\u0241\u0005-\u0000\u0000\u0240\u023f\u0001\u0000"+ + "\u0000\u0000\u0240\u0241\u0001\u0000\u0000\u0000\u0241\u0243\u0001\u0000"+ + "\u0000\u0000\u0242\u0244\u0007\u0001\u0000\u0000\u0243\u0242\u0001\u0000"+ + "\u0000\u0000\u0244\u0245\u0001\u0000\u0000\u0000\u0245\u0243\u0001\u0000"+ + "\u0000\u0000\u0245\u0246\u0001\u0000\u0000\u0000\u0246\u024d\u0001\u0000"+ + "\u0000\u0000\u0247\u0249\u0005.\u0000\u0000\u0248\u024a\u0007\u0001\u0000"+ + "\u0000\u0249\u0248\u0001\u0000\u0000\u0000\u024a\u024b\u0001\u0000\u0000"+ + "\u0000\u024b\u0249\u0001\u0000\u0000\u0000\u024b\u024c\u0001\u0000\u0000"+ + "\u0000\u024c\u024e\u0001\u0000\u0000\u0000\u024d\u0247\u0001\u0000\u0000"+ + "\u0000\u024d\u024e\u0001\u0000\u0000\u0000\u024e\u0080\u0001\u0000\u0000"+ + "\u0000\u024f\u0254\u0005\"\u0000\u0000\u0250\u0253\u0003\u0083A\u0000"+ + "\u0251\u0253\b\u0002\u0000\u0000\u0252\u0250\u0001\u0000\u0000\u0000\u0252"+ + "\u0251\u0001\u0000\u0000\u0000\u0253\u0256\u0001\u0000\u0000\u0000\u0254"+ + "\u0252\u0001\u0000\u0000\u0000\u0254\u0255\u0001\u0000\u0000\u0000\u0255"+ + "\u0257\u0001\u0000\u0000\u0000\u0256\u0254\u0001\u0000\u0000\u0000\u0257"+ + "\u0262\u0005\"\u0000\u0000\u0258\u025d\u0005\'\u0000\u0000\u0259\u025c"+ + "\u0003\u0083A\u0000\u025a\u025c\b\u0003\u0000\u0000\u025b\u0259\u0001"+ + "\u0000\u0000\u0000\u025b\u025a\u0001\u0000\u0000\u0000\u025c\u025f\u0001"+ + "\u0000\u0000\u0000\u025d\u025b\u0001\u0000\u0000\u0000\u025d\u025e\u0001"+ + "\u0000\u0000\u0000\u025e\u0260\u0001\u0000\u0000\u0000\u025f\u025d\u0001"+ + "\u0000\u0000\u0000\u0260\u0262\u0005\'\u0000\u0000\u0261\u024f\u0001\u0000"+ + "\u0000\u0000\u0261\u0258\u0001\u0000\u0000\u0000\u0262\u0082\u0001\u0000"+ + "\u0000\u0000\u0263\u0264\u0005\\\u0000\u0000\u0264\u0268\u0007\u0004\u0000"+ + "\u0000\u0265\u0268\u0003\u0085B\u0000\u0266\u0268\u0003\u0087C\u0000\u0267"+ + "\u0263\u0001\u0000\u0000\u0000\u0267\u0265\u0001\u0000\u0000\u0000\u0267"+ + "\u0266\u0001\u0000\u0000\u0000\u0268\u0084\u0001\u0000\u0000\u0000\u0269"+ + "\u026a\u0005\\\u0000\u0000\u026a\u026b\u0005u\u0000\u0000\u026b\u026c"+ + "\u0003\u0089D\u0000\u026c\u026d\u0003\u0089D\u0000\u026d\u026e\u0003\u0089"+ + "D\u0000\u026e\u026f\u0003\u0089D\u0000\u026f\u0086\u0001\u0000\u0000\u0000"+ + "\u0270\u0272\u0005\\\u0000\u0000\u0271\u0273\u0007\u0005\u0000\u0000\u0272"+ + "\u0271\u0001\u0000\u0000\u0000\u0272\u0273\u0001\u0000\u0000\u0000\u0273"+ + "\u0274\u0001\u0000\u0000\u0000\u0274\u0275\u0007\u0006\u0000\u0000\u0275"+ + "\u0276\u0007\u0006\u0000\u0000\u0276\u0088\u0001\u0000\u0000\u0000\u0277"+ + "\u0278\u0007\u0007\u0000\u0000\u0278\u008a\u0001\u0000\u0000\u0000\u0279"+ + "\u027d\u0007\b\u0000\u0000\u027a\u027c\u0007\t\u0000\u0000\u027b\u027a"+ + "\u0001\u0000\u0000\u0000\u027c\u027f\u0001\u0000\u0000\u0000\u027d\u027b"+ + "\u0001\u0000\u0000\u0000\u027d\u027e\u0001\u0000\u0000\u0000\u027e\u008c"+ + "\u0001\u0000\u0000\u0000\u027f\u027d\u0001\u0000\u0000\u0000\u0280\u0281"+ + "\u0005g\u0000\u0000\u0281\u0282\u0005e\u0000\u0000\u0282\u0283\u0005t"+ + "\u0000\u0000\u0283\u0284\u0005P\u0000\u0000\u0284\u0285\u0005r\u0000\u0000"+ + "\u0285\u0286\u0005o\u0000\u0000\u0286\u0287\u0005p\u0000\u0000\u0287\u0288"+ + "\u0005e\u0000\u0000\u0288\u0289\u0005r\u0000\u0000\u0289\u028a\u0005t"+ + "\u0000\u0000\u028a\u028b\u0005y\u0000\u0000\u028b\u008e\u0001\u0000\u0000"+ + "\u0000\u028c\u028d\u0005?\u0000\u0000\u028d\u0090\u0001\u0000\u0000\u0000"+ + "\u028e\u028f\u0005@\u0000\u0000\u028f\u0092\u0001\u0000\u0000\u0000\u0290"+ + "\u0292\u0007\n\u0000\u0000\u0291\u0290\u0001\u0000\u0000\u0000\u0292\u0293"+ + "\u0001\u0000\u0000\u0000\u0293\u0291\u0001\u0000\u0000\u0000\u0293\u0294"+ + "\u0001\u0000\u0000\u0000\u0294\u0295\u0001\u0000\u0000\u0000\u0295\u0296"+ + "\u0006I\u0000\u0000\u0296\u0094\u0001\u0000\u0000\u0000\u0014\u0000\u00cb"+ + "\u00d9\u01f9\u01ff\u0205\u023d\u0240\u0245\u024b\u024d\u0252\u0254\u025b"+ + "\u025d\u0261\u0267\u0272\u027d\u0293\u0001\u0006\u0000\u0000"; + public static final ATN _ATN = + new ATNDeserializer().deserialize(_serializedATN.toCharArray()); + static { + _decisionToDFA = new DFA[_ATN.getNumberOfDecisions()]; + for (int i = 0; i < _ATN.getNumberOfDecisions(); i++) { + _decisionToDFA[i] = new DFA(_ATN.getDecisionState(i), i); + } + } +} \ No newline at end of file diff --git a/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.tokens b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.tokens new file mode 100644 index 0000000000..3848a35265 --- /dev/null +++ b/modules/core/src/main/antlr4/org/apache/synapse/util/SIEL/gen/ExpressionLexer.tokens @@ -0,0 +1,129 @@ +JSONPATH_FUNCTIONS=1 +VAR=2 +PAYLOAD=3 +HEADERS=4 +ATTRIBUTES=5 +REGISTRY=6 +SECRET=7 +BASE64ENCODE=8 +BASE64DECODE=9 +URLENCODE=10 +URLDECODE=11 +NOW=12 +TODAY=13 +FORMATDATE=14 +ISNUMBER=15 +ISSTRING=16 +ISARRAY=17 +ISOBJECT=18 +ROUND=19 +INTEGER=20 +FLOAT=21 +STRING=22 +BOOLEAN=23 +ABS=24 +FLOOR=25 +CEIL=26 +SQRT=27 +LOG=28 +POW=29 +LENGTH=30 +TOUPPER=31 +TOLOWER=32 +SUBSTRING=33 +STARTSWITH=34 +ENDSWITH=35 +CONTAINS=36 +TRIM=37 +REPLACE=38 +SPLIT=39 +AND=40 +OR=41 +NOT=42 +DOUBLE_DOT=43 +ASTERISK=44 +PLUS=45 +MINUS=46 +DIV=47 +MODULO=48 +EQ=49 +NEQ=50 +GT=51 +LT=52 +GTE=53 +LTE=54 +LPAREN=55 +RPAREN=56 +LBRACKET=57 +RBRACKET=58 +DOT=59 +COMMA=60 +COLON=61 +QUOTE=62 +BOOLEAN_LITERAL=63 +NUMBER=64 +STRING_LITERAL=65 +ID=66 +GETPROPERTY=67 +QUESTION=68 +AT=69 +WS=70 +'var'=2 +'headers'=4 +'attributes'=5 +'registry'=6 +'secret'=7 +'base64encode'=8 +'base64decode'=9 +'urlEncode'=10 +'urlDecode'=11 +'now'=12 +'today'=13 +'formatDate'=14 +'isNumber'=15 +'isString'=16 +'isArray'=17 +'isObject'=18 +'round'=19 +'integer'=20 +'float'=21 +'string'=22 +'boolean'=23 +'abs'=24 +'floor'=25 +'ceil'=26 +'sqrt'=27 +'log'=28 +'pow'=29 +'length'=30 +'toUpper'=31 +'toLower'=32 +'subString'=33 +'startsWith'=34 +'endsWith'=35 +'contains'=36 +'trim'=37 +'replace'=38 +'split'=39 +'..'=43 +'*'=44 +'+'=45 +'-'=46 +'/'=47 +'%'=48 +'=='=49 +'!='=50 +'>'=51 +'<'=52 +'>='=53 +'<='=54 +'('=55 +')'=56 +'['=57 +']'=58 +'.'=59 +','=60 +':'=61 +'getProperty'=67 +'?'=68 +'@'=69 diff --git a/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java b/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java index 47647ee066..3051e3b95b 100644 --- a/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java +++ b/modules/core/src/main/java/org/apache/synapse/SynapseConstants.java @@ -625,4 +625,58 @@ public enum ENDPOINT_TIMEOUT_TYPE { ENDPOINT_TIMEOUT, GLOBAL_TIMEOUT, HTTP_CONNE public static final String JAEGER_SPAN_ID = "jaeger_span_id"; public static final String ANALYTICS_METADATA = "ANALYTICS_METADATA"; + + // Constants related to SIEL + public static final String AND = "and"; + public static final String OR = "or"; + public static final String NOT = "not"; + public static final String TO_LOWER = "toLower"; + public static final String TO_UPPER = "toUpper"; + public static final String LENGTH = "length"; + public static final String SUBSTRING = "subString"; + public static final String STARTS_WITH = "startsWith"; + public static final String ENDS_WITH = "endsWith"; + public static final String CONTAINS = "contains"; + public static final String TRIM = "trim"; + public static final String REPLACE = "replace"; + public static final String SPLIT = "split"; + public static final String NOW = "now"; + public static final String ABS = "abs"; + public static final String CEIL = "ceil"; + public static final String FLOOR = "floor"; + public static final String SQRT = "sqrt"; + public static final String LOG = "log"; + public static final String POW = "pow"; + public static final String B64ENCODE = "base64encode"; + public static final String B64DECODE = "base64decode"; + public static final String URL_ENCODE = "urlEncode"; + public static final String URL_DECODE = "urlDecode"; + public static final String IS_NUMBER = "isNumber"; + public static final String IS_STRING = "isString"; + public static final String IS_ARRAY = "isArray"; + public static final String IS_OBJECT = "isObject"; + + public static final String ROUND = "round"; + public static final String INTEGER = "integer"; + public static final String FLOAT = "float"; + public static final String STRING = "string"; + public static final String BOOLEAN = "boolean"; + + public static final String PAYLOAD = "payload"; + public static final String PAYLOAD_$ = "$"; + public static final String SIEL_IDENTIFIER_START = "#["; + public static final String SIEL_IDENTIFIER_END = "]"; + public static final String AXIS2 = "axis2"; + + public static final class SIELErrors { + public static final String IF_CONDITION_ERROR = "Condition is not a boolean value"; + private static final String INVALID_ARGUMENT = "Invalid argument type provided for %s function"; + private static final String INVALID_OPERATION = "Invalid argument type provided for %s operation"; + public static String getInvalidArgumentMessage(String functionName) { + return String.format(INVALID_ARGUMENT, functionName); + } + public static String getInvalidOperationMessage(String functionName) { + return String.format(INVALID_OPERATION, functionName); + } + } } diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java b/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java index 5b7c45ca36..fcddb88a09 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/PropertyMediatorFactory.java @@ -22,11 +22,13 @@ import org.apache.axiom.om.OMAttribute; import org.apache.axiom.om.OMElement; import org.apache.synapse.Mediator; +import org.apache.synapse.SynapseConstants; import org.apache.synapse.SynapseException; import org.apache.synapse.mediators.Value; import org.apache.synapse.mediators.builtin.PropertyMediator; import org.apache.synapse.util.MediatorPropertyUtils; import org.apache.synapse.util.xpath.SynapseJsonPath; +import org.apache.synapse.util.xpath.SynapseSIELPath; import org.apache.synapse.util.xpath.SynapseXPath; import org.jaxen.JaxenException; @@ -83,6 +85,9 @@ public Mediator createSpecificMediator(OMElement elem, Properties properties) { String nameExpression = nameAttributeValue.substring(1, nameAttributeValue.length() - 1); if(nameExpression.startsWith("json-eval(")) { new SynapseJsonPath(nameExpression.substring(10, nameExpression.length() - 1)); + } else if (nameExpression.startsWith(SynapseConstants.SIEL_IDENTIFIER_START) && + nameExpression.endsWith(SynapseConstants.SIEL_IDENTIFIER_END)) { + new SynapseSIELPath(nameExpression.substring(2, nameExpression.length() - 1)); } else { new SynapseXPath(nameExpression); } diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java index 133aaff73d..77b2c1a650 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePath.java @@ -27,6 +27,7 @@ public abstract class SynapsePath extends AXIOMXPath { public static final String X_PATH = "X_PATH"; public static final String JSON_PATH = "JSON_PATH"; + public static final String SIEL_PATH = "SIEL_PATH"; private String pathType = null; public DOMSynapseXPathNamespaceMap domNamespaceMap = new DOMSynapseXPathNamespaceMap(); @@ -60,9 +61,11 @@ public SynapsePath(String path, String pathType, Log log) throws JaxenException private String inferPathType(String expression) { if (expression.startsWith("json-eval(")) { - return X_PATH; - } else { return JSON_PATH; + } else if(expression.startsWith("#[") && expression.endsWith("]")) { + return SIEL_PATH; + } else { + return X_PATH; } } diff --git a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java index 791c7612e8..b7bdba4635 100644 --- a/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java +++ b/modules/core/src/main/java/org/apache/synapse/config/xml/SynapsePathFactory.java @@ -27,6 +27,7 @@ import org.apache.synapse.SynapseException; import org.apache.synapse.config.SynapsePropertiesLoader; import org.apache.synapse.util.xpath.SynapseJsonPath; +import org.apache.synapse.util.xpath.SynapseSIELPath; import org.apache.synapse.util.xpath.SynapseXPath; import org.jaxen.JaxenException; @@ -49,6 +50,9 @@ public static SynapsePath getSynapsePath(OMElement elem, QName attribName) if(pathAttrib.getAttributeValue().startsWith("json-eval(")) { path = new SynapseJsonPath(pathAttrib.getAttributeValue().substring(10, pathAttrib.getAttributeValue().length() - 1)); + } else if (pathAttrib.getAttributeValue().startsWith(SynapseConstants.SIEL_IDENTIFIER_START) && + pathAttrib.getAttributeValue().endsWith(SynapseConstants.SIEL_IDENTIFIER_END)) { + path = new SynapseSIELPath(pathAttrib.getAttributeValue().substring(2, pathAttrib.getAttributeValue().length() - 1)); } else { try { path = new SynapseXPath(pathAttrib.getAttributeValue()); diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArgumentListNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArgumentListNode.java new file mode 100644 index 0000000000..1656714609 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArgumentListNode.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import java.util.ArrayList; +import java.util.List; + +/** + * This class handles the list of arguments passed to a function. + */ +public class ArgumentListNode implements ExpressionNode { + private final List arguments = new ArrayList<>(); + + public ArgumentListNode() { + } + + public void addArgument(ExpressionNode argument) { + arguments.add(argument); + } + + public List getArguments() { + return arguments; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + return null; + } + +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArrayIndexNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArrayIndexNode.java new file mode 100644 index 0000000000..18dd60d46c --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ArrayIndexNode.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import java.util.ArrayList; +import java.util.List; + +/** + * This class handles the index of an array in AST. + */ +public class ArrayIndexNode implements ExpressionNode { + private final List indexArray; + private final char separator; + + public ArrayIndexNode(ArgumentListNode arguments, char separator) { + this.indexArray = arguments.getArguments(); + this.separator = separator; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + List indexList = new ArrayList<>(); + for (ExpressionNode index : indexArray) { + if (index == null) { + indexList.add(""); + continue; + } + ExpressionResult result = index.evaluate(context); + if (result != null) { + indexList.add(result.asString()); + } + } + return new ExpressionResult(String.join(String.valueOf(separator), indexList)); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/BinaryOperationNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/BinaryOperationNode.java new file mode 100644 index 0000000000..13afc61561 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/BinaryOperationNode.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.SynapseConstants; +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import org.apache.synapse.util.SIEL.exception.EvaluationException; + +import java.util.function.BiFunction; + +/** + * Represents a binary operation between two nodes in AST. + */ +public class BinaryOperationNode implements ExpressionNode { + + private final ExpressionNode left; + private final ExpressionNode right; + private final Operator operator; + + public enum Operator { + ADD("+"), + SUBTRACT("-"), + MULTIPLY("*"), + DIVIDE("/"), + MODULO("%"), + EQUALS("=="), + NOT_EQUALS("!="), + LESS_THAN("<"), + LESS_THAN_OR_EQUAL("<="), + GREATER_THAN(">"), + GREATER_THAN_OR_EQUAL(">="), + AND("and"), + AND_SYMBOL("&&"), + OR("or"), + OR_SYMBOL("||"); + + private final String symbol; + + Operator(String symbol) { + this.symbol = symbol; + } + + public static Operator fromString(String symbol) { + for (Operator op : values()) { + if (op.symbol.equals(symbol)) { + return op; + } + } + throw new IllegalArgumentException("Unsupported operator: " + symbol); + } + } + + public BinaryOperationNode(ExpressionNode left, String operator, ExpressionNode right) { + this.left = left; + this.operator = Operator.fromString(operator.trim().toLowerCase()); + this.right = right; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + ExpressionResult leftValue = left.evaluate(context); + ExpressionResult rightValue = right.evaluate(context); + + switch (operator) { + case ADD: + return handleAddition(leftValue, rightValue); + case SUBTRACT: + case MULTIPLY: + case DIVIDE: + case MODULO: + return handleArithmetic(leftValue, rightValue, operator); + case EQUALS: + return handleEquality(leftValue, rightValue, String::equals); + case NOT_EQUALS: + return handleEquality(leftValue, rightValue, (a, b) -> !a.equals(b)); + case LESS_THAN: + return handleComparison(leftValue, rightValue, (a, b) -> a < b); + case LESS_THAN_OR_EQUAL: + return handleComparison(leftValue, rightValue, (a, b) -> a <= b); + case GREATER_THAN: + return handleComparison(leftValue, rightValue, (a, b) -> a > b); + case GREATER_THAN_OR_EQUAL: + return handleComparison(leftValue, rightValue, (a, b) -> a >= b); + case AND: + case AND_SYMBOL: + case OR: + case OR_SYMBOL: + return handleLogical(leftValue, rightValue, operator); + default: + throw new EvaluationException("Unsupported operator: " + operator); + } + } + + private ExpressionResult handleComparison(ExpressionResult leftValue, ExpressionResult rightValue, + BiFunction comparison) { + if ((leftValue.isDouble() || leftValue.isInteger()) && (rightValue.isDouble() || rightValue.isInteger())) { + return new ExpressionResult(comparison.apply(leftValue.asDouble(), rightValue.asDouble())); + } + throw new EvaluationException(SynapseConstants.SIELErrors.getInvalidOperationMessage("comparison")); + } + + private ExpressionResult handleEquality(ExpressionResult leftValue, ExpressionResult rightValue, + BiFunction comparison) { + return new ExpressionResult(comparison.apply(leftValue.asString(), rightValue.asString())); + } + + private ExpressionResult handleLogical(ExpressionResult leftValue, ExpressionResult rightValue, Operator operator) { + if (leftValue.isBoolean() && rightValue.isBoolean()) { + BiFunction logicOperation = operator + == Operator.AND || operator == Operator.AND_SYMBOL ? (a, b) -> a && b : (a, b) -> a || b; + return new ExpressionResult(logicOperation.apply(leftValue.asBoolean(), rightValue.asBoolean())); + } + throw new EvaluationException(SynapseConstants.SIELErrors.getInvalidOperationMessage("logical")); + } + + private ExpressionResult handleAddition(ExpressionResult leftValue, ExpressionResult rightValue) { + if (leftValue.isDouble() || rightValue.isDouble()) { + return new ExpressionResult(leftValue.asDouble() + rightValue.asDouble()); + } else if (leftValue.isInteger() && rightValue.isInteger()) { + return new ExpressionResult(leftValue.asInt() + rightValue.asInt()); + } else if (leftValue.isString() && rightValue.isString()) { + return new ExpressionResult(leftValue.asString().concat(rightValue.asString())); + } else { + throw new EvaluationException(SynapseConstants.SIELErrors.getInvalidOperationMessage("+")); + } + } + + private ExpressionResult handleArithmetic(ExpressionResult leftValue, ExpressionResult rightValue, + Operator operator) { + if (!leftValue.isNumeric() || !rightValue.isNumeric()) { + throw new EvaluationException(SynapseConstants.SIELErrors.getInvalidOperationMessage(operator.symbol)); + } + boolean isInteger = leftValue.isInteger() && rightValue.isInteger(); + switch (operator) { + case SUBTRACT: + return isInteger ? new ExpressionResult(leftValue.asInt() - rightValue.asInt()) : + new ExpressionResult(leftValue.asDouble() - rightValue.asDouble()); + case MULTIPLY: + return isInteger ? new ExpressionResult(leftValue.asInt() * rightValue.asInt()) : + new ExpressionResult(leftValue.asDouble() * rightValue.asDouble()); + case DIVIDE: + return isInteger ? new ExpressionResult(leftValue.asInt() / rightValue.asInt()) : + new ExpressionResult(leftValue.asDouble() / rightValue.asDouble()); + case MODULO: + return isInteger ? new ExpressionResult(leftValue.asInt() % rightValue.asInt()) : + new ExpressionResult(leftValue.asDouble() % rightValue.asDouble()); + default: + throw new EvaluationException("Unsupported operator: " + operator); + } + } +} \ No newline at end of file diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ConditionalExpressionNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ConditionalExpressionNode.java new file mode 100644 index 0000000000..bcaa29d0b7 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ConditionalExpressionNode.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.SynapseConstants; +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import org.apache.synapse.util.SIEL.exception.EvaluationException; + +/** + * Represents a conditional expression node ( a ? b : c ) in the AST. + */ +public class ConditionalExpressionNode implements ExpressionNode { + + private final ExpressionNode condition; + private final ExpressionNode trueExpression; + private final ExpressionNode falseExpression; + + public ConditionalExpressionNode(ExpressionNode condition, ExpressionNode trueExpression, + ExpressionNode falseExpression) { + this.condition = condition; + this.trueExpression = trueExpression; + this.falseExpression = falseExpression; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + ExpressionResult conditionResult = condition.evaluate(context); + if (conditionResult.isBoolean()) { + return conditionResult.asBoolean() ? trueExpression.evaluate(context) : falseExpression.evaluate(context); + } else { + throw new EvaluationException(SynapseConstants.SIELErrors.IF_CONDITION_ERROR); + } + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionNode.java new file mode 100644 index 0000000000..14d75a2143 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionNode.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.util.SIEL.context.EvaluationContext; + +/** + * Represents a node in the AST. + */ +public interface ExpressionNode { + ExpressionResult evaluate(EvaluationContext context); +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionResult.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionResult.java new file mode 100644 index 0000000000..9abd889f66 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/ExpressionResult.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.synapse.util.SIEL.ast; + +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonPrimitive; +import com.google.gson.internal.LazilyParsedNumber; +import org.apache.synapse.util.SIEL.exception.EvaluationException; + +/** + * This class represents the result of an expression evaluation. + * It can hold values of different types such as String, Number, Boolean, JsonElement, and null. + */ +public class ExpressionResult { + private final Object value; + + // Constructor for String + public ExpressionResult(String value) { + this.value = value; + } + + public ExpressionResult(Number value) { + this.value = value; + } + + // Constructor for int + public ExpressionResult(int value) { + this.value = value; + } + + // Constructor for double + public ExpressionResult(double value) { + this.value = value; + } + + // Constructor for boolean + public ExpressionResult(boolean value) { + this.value = value; + } + + // Constructor for JsonElement + public ExpressionResult(JsonElement value) { + this.value = value; + } + + // Constructor for null + public ExpressionResult() { + this.value = null; + } + + // Method to check if the result is null + public boolean isNull() { + return value == null || (value instanceof JsonElement && value.equals(JsonNull.INSTANCE)); + } + + // Method to get value as String + public String asString() { + if (value == null) { + return null; + } else if (value instanceof String) { + // if quoted, remove quotes + if (((String) value).startsWith("\"") && ((String) value).endsWith("\"")) { + return ((String) value).substring(1, ((String) value).length() - 1); + } else if (((String) value).startsWith("'") && ((String) value).endsWith("'")) { + return ((String) value).substring(1, ((String) value).length() - 1); + } + return (String) value; + } else if (value instanceof JsonPrimitive && ((JsonPrimitive) value).isString()) { + return ((JsonPrimitive) value).getAsString(); + } + return value.toString(); // Fallback to toString() for other types + } + + // Method to get value as int + public int asInt() { + if (value instanceof Number) { + return ((Number) value).intValue(); + } else if (value instanceof JsonPrimitive && ((JsonPrimitive) value).isNumber()) { + return ((JsonPrimitive) value).getAsInt(); + } + throw new EvaluationException("Value : " + value + " cannot be converted to int"); + } + + // Method to get value as double + public double asDouble() { + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } else if (value instanceof JsonPrimitive && ((JsonPrimitive) value).isNumber()) { + return ((JsonPrimitive) value).getAsDouble(); + } + throw new EvaluationException("Value : " + value + " cannot be converted to double"); + } + + // Method to get value as boolean + public boolean asBoolean() { + if (value instanceof Boolean) { + return (Boolean) value; + } else if (value instanceof JsonPrimitive && ((JsonPrimitive) value).isBoolean()) { + return ((JsonPrimitive) value).getAsBoolean(); + } + throw new EvaluationException("Value : " + value + " cannot be converted to boolean"); + } + + // Method to get value as JsonElement + public JsonElement asJsonElement() { + if (value instanceof JsonElement) { + return (JsonElement) value; + } + throw new EvaluationException("Value is not a JsonElement"); + } + + // Method to check the actual type of the result + public Class getType() { + if (value == null) { + return null; + } + return value.getClass(); + } + + public boolean isNumeric() { + return isInteger() || isDouble(); + } + public boolean isInteger() { + return value instanceof Integer || (value instanceof JsonPrimitive && isInteger((JsonPrimitive) value)); + } + + public boolean isDouble() { + return value instanceof Double || (value instanceof JsonPrimitive && isDouble((JsonPrimitive) value)); + } + + public boolean isBoolean() { + return value instanceof Boolean || (value instanceof JsonPrimitive && ((JsonPrimitive) value).isBoolean()); + } + + public boolean isString() { + return value instanceof String || (value instanceof JsonPrimitive && ((JsonPrimitive) value).isString()); + } + + public boolean isObject() { + return value instanceof JsonElement && ((JsonElement) value).isJsonObject(); + } + + public boolean isArray() { + return value instanceof JsonElement && ((JsonElement) value).isJsonArray(); + } + + public boolean isJsonPrimitive() { + return value instanceof JsonPrimitive; + } + + private boolean isInteger(JsonPrimitive jsonPrimitive) { + if (jsonPrimitive.isNumber()) { + Number number = jsonPrimitive.getAsNumber(); + // Check if the number is an instance of integer types (int, long, short) + boolean initialCheck = number instanceof Integer || number instanceof Long || number instanceof Short; + if (!initialCheck && number instanceof LazilyParsedNumber) { + // Check if the number is an instance of integer types (int, long, short) + String numberString = number.toString(); + try { + Integer.parseInt(numberString); + return true; + } catch (NumberFormatException e) { + return false; + } + } + return initialCheck; + } + return false; // Not a number, so it's not an integer + } + + private boolean isDouble(JsonPrimitive jsonPrimitive) { + if (jsonPrimitive.isNumber()) { + Number number = jsonPrimitive.getAsNumber(); + // Check if the number is an instance of floating-point types (float, double) + boolean initialCheck = number instanceof Float || number instanceof Double; + if (!initialCheck && number instanceof LazilyParsedNumber) { + // Check if the number is an instance of integer types (int, long, short) + String numberString = number.toString(); + try { + Double.parseDouble(numberString); + return true; + } catch (NumberFormatException e) { + return false; + } + } + } + return false; // Not a number, so it's not a double + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/FilterExpressionNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/FilterExpressionNode.java new file mode 100644 index 0000000000..c7527a30b8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/FilterExpressionNode.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import org.apache.synapse.util.SIEL.utils.ExpressionUtils; + +import java.util.Map; + +/** + * Represents a json-path filter expression node in the AST. + */ +public class FilterExpressionNode implements ExpressionNode { + + + private String expression; + private final Map arguments; + + public FilterExpressionNode(String expression, Map arguments) { + this.expression = expression; + this.arguments = arguments; + } + + /** + * return the formatted JSONPath filter expression. + * Not evaluating here. + */ + @Override + public ExpressionResult evaluate(EvaluationContext context) { + for (Map.Entry entry : arguments.entrySet()) { + if (entry.getValue() != null) { + ExpressionResult result = entry.getValue().evaluate(context); + if (result != null) { + String regex = ExpressionUtils.escapeSpecialCharacters(entry.getKey()); + String resultString = result.asString(); + if (result.isString()) { + resultString = "\"" + resultString + "\""; + } + expression = expression.replaceFirst(regex, resultString); + } + } + } + return new ExpressionResult("?" + expression); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/HeadersAndPropertiesAccessNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/HeadersAndPropertiesAccessNode.java new file mode 100644 index 0000000000..c71b99bb00 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/HeadersAndPropertiesAccessNode.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.synapse.util.SIEL.ast; + +import org.apache.synapse.util.SIEL.context.EvaluationContext; + +/** + * Represents a node in the abstract syntax tree that provides access to headers and properties. + */ +public class HeadersAndPropertiesAccessNode implements ExpressionNode { + private final String scope; + + public enum Type { + HEADER, + PROPERTY, + CONFIG + } + + private final Type type; + + // property key or header name + private final ExpressionNode key; + + public HeadersAndPropertiesAccessNode(ExpressionNode node, Type type) { + this.key = node; + this.type = type; + scope = null; + } + + public HeadersAndPropertiesAccessNode(ExpressionNode node, String scope) { + this.key = node; + this.scope = scope; + this.type = Type.PROPERTY; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + if (key != null) { + String name = key.evaluate(context).asString(); + if (type.equals(Type.HEADER)) { + Object value = context.getHeader(name); + return new ExpressionResult(value != null ? value.toString() : ""); + } else { + Object value = context.getProperty(name, scope); + return new ExpressionResult(value != null ? value.toString() : ""); + } + } + return null; + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/LiteralNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/LiteralNode.java new file mode 100644 index 0000000000..17a1aecc21 --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/LiteralNode.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import org.apache.synapse.util.SIEL.context.EvaluationContext; + +/** + * Represents a leaf node in the AST that holds a literal value. + */ +public class LiteralNode implements ExpressionNode { + private final String value; + private ArgumentListNode parameterList = new ArgumentListNode(); + + public enum Type { + NUMBER, + STRING, + BOOLEAN, + NULL, + ARRAY + } + + private final Type type; + + public LiteralNode(String value, Type type) { + this.value = value; + this.type = type; + } + + public LiteralNode(ArgumentListNode value, Type type) { + this.parameterList = value; + this.type = type; + this.value = ""; + } + + @Override + public ExpressionResult evaluate(EvaluationContext context) { + switch (type) { + case NUMBER: + return parseNumber(value); + case STRING: + return new ExpressionResult(value); + case BOOLEAN: + return new ExpressionResult(Boolean.parseBoolean(value)); + case NULL: + return new ExpressionResult(); + case ARRAY: + return parseArray(context); + default: + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private ExpressionResult parseNumber(String value) { + try { + return new ExpressionResult(Integer.parseInt(value)); + } catch (NumberFormatException e1) { + try { + return new ExpressionResult(Float.parseFloat(value)); + } catch (NumberFormatException e2) { + try { + return new ExpressionResult(Double.parseDouble(value)); + } catch (NumberFormatException e3) { + throw new IllegalArgumentException("Value " + value + " is not a number"); + } + } + } + } + + private ExpressionResult parseArray(EvaluationContext context) { + JsonArray jsonArray = new JsonArray(); + for (ExpressionNode expressionNode : parameterList.getArguments()) { + ExpressionResult result = expressionNode.evaluate(context); + if (result.getType().equals(JsonElement.class)) { + jsonArray.add(result.asJsonElement()); + } else if (result.isInteger()) { + jsonArray.add(result.asInt()); + } else if (result.isDouble()) { + jsonArray.add(result.asDouble()); + } else { + jsonArray.add(result.asString()); + } + } + return new ExpressionResult(jsonArray); + } +} diff --git a/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/PayloadAccessNode.java b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/PayloadAccessNode.java new file mode 100644 index 0000000000..7608bc62ac --- /dev/null +++ b/modules/core/src/main/java/org/apache/synapse/util/SIEL/ast/PayloadAccessNode.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 LLC. licenses this file 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, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.synapse.util.SIEL.ast; + +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSyntaxException; +import com.jayway.jsonpath.Configuration; +import com.jayway.jsonpath.JsonPath; +import com.jayway.jsonpath.Option; +import com.jayway.jsonpath.PathNotFoundException; +import com.jayway.jsonpath.spi.json.GsonJsonProvider; +import com.jayway.jsonpath.spi.json.JsonProvider; +import com.jayway.jsonpath.spi.mapper.GsonMappingProvider; +import com.jayway.jsonpath.spi.mapper.MappingProvider; +import org.apache.commons.lang3.StringUtils; +import org.apache.synapse.SynapseConstants; +import org.apache.synapse.util.SIEL.context.EvaluationContext; +import org.apache.synapse.util.SIEL.exception.EvaluationException; +import org.apache.synapse.util.SIEL.utils.ExpressionUtils; + +import java.io.IOException; +import java.util.EnumSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +/** + * Represents a node in the AST that accesses a value in the payload or variable. + * Resolve placeholders in the expression and evaluate the expression using JSONPath. + */ +public class PayloadAccessNode implements ExpressionNode { + private String expression; + private final Map arguments; + + private final boolean isVariable; + + public PayloadAccessNode(String expression, Map arguments, boolean isVariable) { + this.expression = expression; + this.arguments = arguments; + this.isVariable = isVariable; + Configuration.setDefaults(new Configuration.Defaults() { + private final JsonProvider jsonProvider = new GsonJsonProvider(new GsonBuilder().serializeNulls().create()); + private final MappingProvider mappingProvider = new GsonMappingProvider(); + + public JsonProvider jsonProvider() { + return jsonProvider; + } + + public MappingProvider mappingProvider() { + return mappingProvider; + } + + public Set