From 5620be211ca81549ab1d420e2042c398e056e4de Mon Sep 17 00:00:00 2001 From: Tim Voronov Date: Fri, 21 Dec 2018 23:14:41 -0500 Subject: [PATCH] Next (#214) * Renamed DOCUMENT to PAGE * Added PageLoadParams * Added PageLoadParams * Renamed LoadPageParams -> PageLoadParams * Added support for context.Done() (#201) * Bug/#189 operators precedence (#202) * Fixed math operators precedence * Fixed logical operators precedence * Fixed array operator * Added support for parentheses to enforce a different operator evaluation order * Feature/#200 drivers (#209) * Added new interfaces * Renamed dynamic to cdp driver * Renamed drivers * Added ELEMENT_EXISTS function (#210) * Renamed back PAGE to DOCUMENT (#211) * Added Getter and Setter interfaces --- cli/exec.go | 11 +- cli/options.go | 34 +- cli/repl.go | 11 +- e2e/main.go | 26 +- e2e/runner/runner.go | 24 +- e2e/tests/doc_element_exists.fql | 10 + e2e/tests/doc_element_exists_d.fql | 10 + e2e/tests/el_element_exists.fql | 12 + e2e/tests/el_element_exists_d.fql | 12 + e2e/tests/page_load_params_d.fql | 6 + examples/embedded.go | 8 +- examples/wait_class.fql | 1 - pkg/compiler/compiler_precedence_test.go | 65 + pkg/compiler/visitor.go | 163 +- pkg/{html/dynamic => drivers/cdp}/document.go | 113 +- pkg/{html/dynamic => drivers/cdp}/driver.go | 49 +- pkg/{html/dynamic => drivers/cdp}/element.go | 35 +- .../dynamic => drivers/cdp}/eval/eval.go | 0 .../dynamic => drivers/cdp}/events/broker.go | 0 .../cdp}/events/broker_test.go | 2 +- .../cdp}/events/dispatch.go | 2 +- .../dynamic => drivers/cdp}/events/wait.go | 2 +- pkg/{html/dynamic => drivers/cdp}/helpers.go | 8 +- pkg/{html/dynamic => drivers/cdp}/options.go | 12 +- pkg/{html => drivers}/common/attrs.go | 0 pkg/{html => drivers}/common/lazy.go | 0 pkg/{html => drivers}/common/types.go | 0 pkg/{html => drivers}/common/ua.go | 0 pkg/drivers/driver.go | 65 + pkg/{html/static => drivers/http}/document.go | 2 +- .../static => drivers/http}/document_test.go | 6 +- pkg/{html/static => drivers/http}/driver.go | 46 +- pkg/{html/static => drivers/http}/element.go | 14 +- .../static => drivers/http}/element_test.go | 20 +- pkg/{html/static => drivers/http}/options.go | 5 +- pkg/html/driver.go | 41 - pkg/parser/antlr/FqlLexer.g4 | 6 +- pkg/parser/antlr/FqlLexer.tokens | 28 +- pkg/parser/antlr/FqlParser.g4 | 32 +- pkg/parser/fql/FqlLexer.interp | 20 +- pkg/parser/fql/FqlLexer.tokens | 28 +- pkg/parser/fql/FqlParser.interp | 22 +- pkg/parser/fql/FqlParser.tokens | 28 +- pkg/parser/fql/fql_lexer.go | 40 +- pkg/parser/fql/fql_parser.go | 1812 +++++++++-------- pkg/parser/fql/fqlparser_base_listener.go | 36 +- pkg/parser/fql/fqlparser_base_visitor.go | 14 +- pkg/parser/fql/fqlparser_listener.go | 36 +- pkg/parser/fql/fqlparser_visitor.go | 18 +- pkg/runtime/core/scope.go | 16 +- pkg/runtime/core/value.go | 14 + pkg/runtime/core/value_test.go | 14 +- pkg/runtime/expressions/block.go | 32 +- pkg/runtime/expressions/block_test.go | 158 ++ pkg/runtime/expressions/body.go | 6 + pkg/runtime/expressions/body_test.go | 31 +- pkg/runtime/expressions/data_source.go | 67 +- pkg/runtime/expressions/data_source_test.go | 35 + pkg/runtime/expressions/for.go | 111 +- pkg/runtime/expressions/func_call.go | 39 +- pkg/runtime/expressions/func_call_test.go | 89 + pkg/runtime/expressions/operators/math.go | 9 +- pkg/runtime/expressions/return.go | 15 +- pkg/runtime/expressions/return_test.go | 24 +- pkg/runtime/program.go | 9 +- pkg/runtime/program_test.go | 29 + pkg/runtime/values/binary.go | 44 +- pkg/runtime/values/helpers.go | 26 +- pkg/runtime/values/html.go | 144 +- pkg/stdlib/html/click.go | 5 +- pkg/stdlib/html/click_all.go | 3 +- pkg/stdlib/html/document.go | 96 +- pkg/stdlib/html/download.go | 44 + pkg/stdlib/html/element_exists.go | 22 + pkg/stdlib/html/hover.go | 6 +- pkg/stdlib/html/input.go | 11 +- pkg/stdlib/html/lib.go | 34 +- pkg/stdlib/html/navigate.go | 3 +- pkg/stdlib/html/navigate_back.go | 3 +- pkg/stdlib/html/navigate_forward.go | 3 +- pkg/stdlib/html/pagination.go | 7 +- .../html/{document_parse.go => parse.go} | 11 +- pkg/stdlib/html/{blob.go => pdf.go} | 309 +-- pkg/stdlib/html/screenshot.go | 163 ++ pkg/stdlib/html/scroll_bottom.go | 4 +- pkg/stdlib/html/scroll_element.go | 6 +- pkg/stdlib/html/scroll_top.go | 4 +- pkg/stdlib/html/select.go | 10 +- pkg/stdlib/html/wait_class.go | 9 +- pkg/stdlib/html/wait_class_all.go | 3 +- pkg/stdlib/html/wait_element.go | 3 +- pkg/stdlib/html/wait_navigation.go | 3 +- 92 files changed, 2953 insertions(+), 1656 deletions(-) create mode 100644 e2e/tests/doc_element_exists.fql create mode 100644 e2e/tests/doc_element_exists_d.fql create mode 100644 e2e/tests/el_element_exists.fql create mode 100644 e2e/tests/el_element_exists_d.fql create mode 100644 e2e/tests/page_load_params_d.fql create mode 100644 pkg/compiler/compiler_precedence_test.go rename pkg/{html/dynamic => drivers/cdp}/document.go (88%) rename pkg/{html/dynamic => drivers/cdp}/driver.go (81%) rename pkg/{html/dynamic => drivers/cdp}/element.go (96%) rename pkg/{html/dynamic => drivers/cdp}/eval/eval.go (100%) rename pkg/{html/dynamic => drivers/cdp}/events/broker.go (100%) rename pkg/{html/dynamic => drivers/cdp}/events/broker_test.go (99%) rename pkg/{html/dynamic => drivers/cdp}/events/dispatch.go (95%) rename pkg/{html/dynamic => drivers/cdp}/events/wait.go (96%) rename pkg/{html/dynamic => drivers/cdp}/helpers.go (97%) rename pkg/{html/dynamic => drivers/cdp}/options.go (72%) rename pkg/{html => drivers}/common/attrs.go (100%) rename pkg/{html => drivers}/common/lazy.go (100%) rename pkg/{html => drivers}/common/types.go (100%) rename pkg/{html => drivers}/common/ua.go (100%) create mode 100644 pkg/drivers/driver.go rename pkg/{html/static => drivers/http}/document.go (98%) rename pkg/{html/static => drivers/http}/document_test.go (99%) rename pkg/{html/static => drivers/http}/driver.go (78%) rename pkg/{html/static => drivers/http}/element.go (95%) rename pkg/{html/static => drivers/http}/element_test.go (97%) rename pkg/{html/static => drivers/http}/options.go (96%) delete mode 100644 pkg/html/driver.go create mode 100644 pkg/runtime/expressions/block_test.go create mode 100644 pkg/runtime/expressions/func_call_test.go create mode 100644 pkg/stdlib/html/download.go create mode 100644 pkg/stdlib/html/element_exists.go rename pkg/stdlib/html/{document_parse.go => parse.go} (61%) rename pkg/stdlib/html/{blob.go => pdf.go} (50%) create mode 100644 pkg/stdlib/html/screenshot.go diff --git a/cli/exec.go b/cli/exec.go index c799caf0..dac8c0ec 100644 --- a/cli/exec.go +++ b/cli/exec.go @@ -38,7 +38,16 @@ func Exec(query string, opts Options) { l := NewLogger() - ctx, cancel := context.WithCancel(opts.WithContext(context.Background())) + ctx, err := opts.WithContext(context.Background()) + + if err != nil { + fmt.Println("Failed to register HTML drivers") + fmt.Println(err) + os.Exit(1) + return + } + + ctx, cancel := context.WithCancel(ctx) c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP) diff --git a/cli/options.go b/cli/options.go index f2756bee..9f0a4cc7 100644 --- a/cli/options.go +++ b/cli/options.go @@ -2,9 +2,9 @@ package cli import ( "context" - "github.com/MontFerret/ferret/pkg/html" - "github.com/MontFerret/ferret/pkg/html/dynamic" - "github.com/MontFerret/ferret/pkg/html/static" + "github.com/MontFerret/ferret/pkg/drivers" + "github.com/MontFerret/ferret/pkg/drivers/cdp" + "github.com/MontFerret/ferret/pkg/drivers/http" ) type Options struct { @@ -15,19 +15,29 @@ type Options struct { ShowTime bool } -func (opts Options) WithContext(ctx context.Context) context.Context { - ctx = html.WithDynamicDriver( +func (opts Options) WithContext(ctx context.Context) (context.Context, error) { + var err error + + ctx = drivers.WithDynamic( ctx, - dynamic.WithCDP(opts.Cdp), - dynamic.WithProxy(opts.Proxy), - dynamic.WithUserAgent(opts.UserAgent), + cdp.NewDriver( + cdp.WithAddress(opts.Cdp), + cdp.WithProxy(opts.Proxy), + cdp.WithUserAgent(opts.UserAgent), + ), ) - ctx = html.WithStaticDriver( + if err != nil { + return ctx, err + } + + ctx = drivers.WithStatic( ctx, - static.WithProxy(opts.Proxy), - static.WithUserAgent(opts.UserAgent), + http.NewDriver( + http.WithProxy(opts.Proxy), + http.WithUserAgent(opts.UserAgent), + ), ) - return ctx + return ctx, err } diff --git a/cli/repl.go b/cli/repl.go index 15c90c23..e7f05a24 100644 --- a/cli/repl.go +++ b/cli/repl.go @@ -42,7 +42,16 @@ func Repl(version string, opts Options) { l := NewLogger() - ctx, cancel := context.WithCancel(opts.WithContext(context.Background())) + ctx, err := opts.WithContext(context.Background()) + + if err != nil { + fmt.Println("Failed to register HTML drivers") + fmt.Println(err) + os.Exit(1) + return + } + + ctx, cancel := context.WithCancel(ctx) c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP) diff --git a/e2e/main.go b/e2e/main.go index 8f084523..9433b798 100644 --- a/e2e/main.go +++ b/e2e/main.go @@ -3,12 +3,12 @@ package main import ( "flag" "fmt" - "os" - "path/filepath" - "github.com/MontFerret/ferret/e2e/runner" "github.com/MontFerret/ferret/e2e/server" "github.com/rs/zerolog" + "os" + "path/filepath" + "regexp" ) var ( @@ -29,6 +29,12 @@ var ( "http://0.0.0.0:9222", "address of remote Chrome instance", ) + + filter = flag.String( + "filter", + "", + "regexp expression to filter out tests", + ) ) func main() { @@ -48,6 +54,19 @@ func main() { Dir: filepath.Join(*pagesDir, "dynamic"), }) + var filterR *regexp.Regexp + + if *filter != "" { + r, err := regexp.Compile(*filter) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + filterR = r + } + go func() { if err := static.Start(); err != nil { logger.Info().Timestamp().Msg("shutting down the static pages server") @@ -79,6 +98,7 @@ func main() { DynamicServerAddress: fmt.Sprintf("http://0.0.0.0:%d", dynamicPort), CDPAddress: *cdp, Dir: *testsDir, + Filter: filterR, }) err := r.Run() diff --git a/e2e/runner/runner.go b/e2e/runner/runner.go index 913f103c..9e8dae55 100644 --- a/e2e/runner/runner.go +++ b/e2e/runner/runner.go @@ -4,14 +4,16 @@ import ( "context" "encoding/json" "github.com/MontFerret/ferret/pkg/compiler" - "github.com/MontFerret/ferret/pkg/html" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/drivers" + "github.com/MontFerret/ferret/pkg/drivers/cdp" + "github.com/MontFerret/ferret/pkg/drivers/http" "github.com/MontFerret/ferret/pkg/runtime" "github.com/pkg/errors" "github.com/rs/zerolog" "io/ioutil" "os" "path/filepath" + "regexp" "time" ) @@ -21,6 +23,7 @@ type ( DynamicServerAddress string CDPAddress string Dir string + Filter *regexp.Regexp } Result struct { @@ -102,7 +105,15 @@ func (r *Runner) runQueries(dir string) ([]Result, error) { // read scripts for _, f := range files { - fName := filepath.Join(dir, f.Name()) + n := f.Name() + + if r.settings.Filter != nil { + if r.settings.Filter.Match([]byte(n)) != true { + continue + } + } + + fName := filepath.Join(dir, n) b, err := ioutil.ReadFile(fName) if err != nil { @@ -134,11 +145,12 @@ func (r *Runner) runQuery(c *compiler.FqlCompiler, name, script string) Result { } ctx := context.Background() - ctx = html.WithDynamicDriver( + ctx = drivers.WithDynamic( ctx, - dynamic.WithCDP(r.settings.CDPAddress), + cdp.NewDriver(cdp.WithAddress(r.settings.CDPAddress)), ) - ctx = html.WithStaticDriver(ctx) + + ctx = drivers.WithStatic(ctx, http.NewDriver()) out, err := p.Run( ctx, diff --git a/e2e/tests/doc_element_exists.fql b/e2e/tests/doc_element_exists.fql new file mode 100644 index 00000000..973e26f6 --- /dev/null +++ b/e2e/tests/doc_element_exists.fql @@ -0,0 +1,10 @@ +LET url = @static + '/overview.html' +LET doc = DOCUMENT(url) + +LET expectedP = TRUE +LET actualP = ELEMENT_EXISTS(doc, '.section-nav') + +LET expectedN = FALSE +LET actualN = ELEMENT_EXISTS(doc, '.foo-bar') + +RETURN EXPECT(expectedP + expectedN, actualP + expectedN) \ No newline at end of file diff --git a/e2e/tests/doc_element_exists_d.fql b/e2e/tests/doc_element_exists_d.fql new file mode 100644 index 00000000..e3e4142b --- /dev/null +++ b/e2e/tests/doc_element_exists_d.fql @@ -0,0 +1,10 @@ +LET url = @dynamic +LET doc = DOCUMENT(url) + +LET expectedP = TRUE +LET actualP = ELEMENT_EXISTS(doc, '.text-center') + +LET expectedN = FALSE +LET actualN = ELEMENT_EXISTS(doc, '.foo-bar') + +RETURN EXPECT(expectedP + expectedN, actualP + expectedN) \ No newline at end of file diff --git a/e2e/tests/el_element_exists.fql b/e2e/tests/el_element_exists.fql new file mode 100644 index 00000000..6225f672 --- /dev/null +++ b/e2e/tests/el_element_exists.fql @@ -0,0 +1,12 @@ +LET url = @static + '/value.html' +LET doc = DOCUMENT(url) + +LET el = ELEMENT(doc, "#listings_table") + +LET expectedP = TRUE +LET actualP = ELEMENT_EXISTS(el, '.odd') + +LET expectedN = FALSE +LET actualN = ELEMENT_EXISTS(el, '.foo-bar') + +RETURN EXPECT(expectedP + expectedN, actualP + expectedN) \ No newline at end of file diff --git a/e2e/tests/el_element_exists_d.fql b/e2e/tests/el_element_exists_d.fql new file mode 100644 index 00000000..ac2be8d7 --- /dev/null +++ b/e2e/tests/el_element_exists_d.fql @@ -0,0 +1,12 @@ +LET url = @dynamic +LET doc = DOCUMENT(url) + +LET el = ELEMENT(doc, "#root") + +LET expectedP = TRUE +LET actualP = ELEMENT_EXISTS(el, '.jumbotron') + +LET expectedN = FALSE +LET actualN = ELEMENT_EXISTS(el, '.foo-bar') + +RETURN EXPECT(expectedP + expectedN, actualP + expectedN) \ No newline at end of file diff --git a/e2e/tests/page_load_params_d.fql b/e2e/tests/page_load_params_d.fql new file mode 100644 index 00000000..4bb1fc08 --- /dev/null +++ b/e2e/tests/page_load_params_d.fql @@ -0,0 +1,6 @@ +LET url = @dynamic +LET doc = DOCUMENT(url, { + dynamic: true +}) + +RETURN EXPECT(doc.url, url) \ No newline at end of file diff --git a/examples/embedded.go b/examples/embedded.go index e4128eae..26ceefaa 100644 --- a/examples/embedded.go +++ b/examples/embedded.go @@ -4,10 +4,12 @@ import ( "context" "encoding/json" "fmt" + "github.com/MontFerret/ferret/pkg/drivers/cdp" + "github.com/MontFerret/ferret/pkg/drivers/http" "os" "github.com/MontFerret/ferret/pkg/compiler" - "github.com/MontFerret/ferret/pkg/html" + "github.com/MontFerret/ferret/pkg/drivers" ) type Topic struct { @@ -60,8 +62,8 @@ func getTopTenTrendingTopics() ([]*Topic, error) { // enable HTML drivers // by default, Ferret Runtime knows nothing about HTML drivers // all HTML manipulations are done via functions from standard library - ctx = html.WithDynamicDriver(ctx) - ctx = html.WithStaticDriver(ctx) + ctx = drivers.WithDynamic(ctx, cdp.NewDriver()) + ctx = drivers.WithStatic(ctx, http.NewDriver()) out, err := program.Run(ctx) diff --git a/examples/wait_class.fql b/examples/wait_class.fql index f179989c..6deef221 100644 --- a/examples/wait_class.fql +++ b/examples/wait_class.fql @@ -1,5 +1,4 @@ LET doc = DOCUMENT("http://getbootstrap.com/docs/4.1/components/collapse/", true) - LET el = ELEMENT(doc, "#collapseTwo") CLICK(doc, "#headingTwo > h5 > button") diff --git a/pkg/compiler/compiler_precedence_test.go b/pkg/compiler/compiler_precedence_test.go new file mode 100644 index 00000000..5306be3f --- /dev/null +++ b/pkg/compiler/compiler_precedence_test.go @@ -0,0 +1,65 @@ +package compiler_test + +import ( + "context" + "github.com/MontFerret/ferret/pkg/compiler" + "testing" + + . "github.com/smartystreets/goconvey/convey" +) + +func TestPrecedence(t *testing.T) { + Convey("Math operators", t, func() { + Convey("2 + 2 * 2", func() { + c := compiler.New() + + p := c.MustCompile(`RETURN 2 + 2 * 2`) + + out := p.MustRun(context.Background()) + + So(string(out), ShouldEqual, "6") + }) + + Convey("2 * 2 + 2", func() { + c := compiler.New() + + p := c.MustCompile(`RETURN 2 * 2 + 2`) + + out := p.MustRun(context.Background()) + + So(string(out), ShouldEqual, "6") + }) + + Convey("2 * (2 + 2)", func() { + c := compiler.New() + + p := c.MustCompile(`RETURN 2 * (2 + 2)`) + + out := p.MustRun(context.Background()) + + So(string(out), ShouldEqual, "8") + }) + }) + + Convey("Logical", t, func() { + Convey("TRUE OR TRUE AND FALSE", func() { + c := compiler.New() + + p := c.MustCompile(`RETURN TRUE OR TRUE AND FALSE`) + + out := p.MustRun(context.Background()) + + So(string(out), ShouldEqual, "true") + }) + + Convey("FALSE AND TRUE OR TRUE", func() { + c := compiler.New() + + p := c.MustCompile(`RETURN FALSE AND TRUE OR TRUE`) + + out := p.MustRun(context.Background()) + + So(string(out), ShouldEqual, "true") + }) + }) +} diff --git a/pkg/compiler/visitor.go b/pkg/compiler/visitor.go index 9290b5c0..8b87e9a2 100644 --- a/pkg/compiler/visitor.go +++ b/pkg/compiler/visitor.go @@ -352,10 +352,16 @@ func (v *visitor) doVisitFilterClause(ctx *fql.FilterClauseContext, scope *scope return operators.NewEqualityOperator(v.getSourceMap(ctx), left, right, equalityOp.GetText()) } - logicalOp := exp.LogicalOperator() + logicalAndOp := exp.LogicalAndOperator() - if logicalOp != nil { - return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalOp.GetText()) + if logicalAndOp != nil { + return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalAndOp.GetText()) + } + + logicalOrOp := exp.LogicalOrOperator() + + if logicalOrOp != nil { + return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, logicalOrOp.GetText()) } } else { // should be unary operator @@ -1078,7 +1084,21 @@ func (v *visitor) doVisitAllExpressions(contexts []fql.IExpressionContext, scope } func (v *visitor) doVisitMathOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { - mathOp := ctx.MathOperator().(*fql.MathOperatorContext) + var operator operators.MathOperatorType + multiCtx := ctx.MultiplicativeOperator() + + if multiCtx != nil { + operator = operators.MathOperatorType(multiCtx.GetText()) + } else { + additiveCtx := ctx.AdditiveOperator() + + if additiveCtx == nil { + return nil, ErrInvalidToken + } + + operator = operators.MathOperatorType(additiveCtx.GetText()) + } + exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) if err != nil { @@ -1089,10 +1109,10 @@ func (v *visitor) doVisitMathOperator(ctx *fql.ExpressionContext, scope *scope) right := exps[1] return operators.NewMathOperator( - v.getSourceMap(mathOp), + v.getSourceMap(ctx), left, right, - operators.MathOperatorType(mathOp.GetText()), + operator, ) } @@ -1115,7 +1135,22 @@ func (v *visitor) doVisitUnaryOperator(ctx *fql.ExpressionContext, scope *scope) } func (v *visitor) doVisitLogicalOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { - logicalOp := ctx.LogicalOperator().(*fql.LogicalOperatorContext) + var operator string + + logicalAndOp := ctx.LogicalAndOperator() + + if logicalAndOp != nil { + operator = logicalAndOp.GetText() + } else { + logicalOrOp := ctx.LogicalOrOperator() + + if logicalOrOp == nil { + return nil, ErrInvalidToken + } + + operator = logicalOrOp.GetText() + } + exps, err := v.doVisitAllExpressions(ctx.AllExpression(), scope) if err != nil { @@ -1125,7 +1160,7 @@ func (v *visitor) doVisitLogicalOperator(ctx *fql.ExpressionContext, scope *scop left := exps[0] right := exps[1] - return operators.NewLogicalOperator(v.getSourceMap(logicalOp), left, right, logicalOp.GetText()) + return operators.NewLogicalOperator(v.getSourceMap(ctx), left, right, operator) } func (v *visitor) doVisitEqualityOperator(ctx *fql.ExpressionContext, scope *scope) (core.OperatorExpression, error) { @@ -1206,13 +1241,83 @@ func (v *visitor) doVisitArrayOperator(ctx *fql.ExpressionContext, scope *scope) ) } +func (v *visitor) doVisitExpressionGroup(ctx *fql.ExpressionGroupContext, scope *scope) (core.Expression, error) { + exp := ctx.Expression() + + if exp == nil { + return nil, ErrInvalidToken + } + + return v.doVisitExpression(exp.(*fql.ExpressionContext), scope) +} + func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (core.Expression, error) { + seq := ctx.ExpressionGroup() + + if seq != nil { + return v.doVisitExpressionGroup(seq.(*fql.ExpressionGroupContext), scope) + } + + member := ctx.MemberExpression() + + if member != nil { + return v.doVisitMemberExpression(member.(*fql.MemberExpressionContext), scope) + } + + funCall := ctx.FunctionCallExpression() + + if funCall != nil { + return v.doVisitFunctionCallExpression(funCall.(*fql.FunctionCallExpressionContext), scope) + } + notOp := ctx.UnaryOperator() if notOp != nil { return v.doVisitUnaryOperator(ctx, scope) } + multiOp := ctx.MultiplicativeOperator() + + if multiOp != nil { + return v.doVisitMathOperator(ctx, scope) + } + + addOp := ctx.AdditiveOperator() + + if addOp != nil { + return v.doVisitMathOperator(ctx, scope) + } + + arrOp := ctx.ArrayOperator() + + if arrOp != nil { + return v.doVisitArrayOperator(ctx, scope) + } + + equalityOp := ctx.EqualityOperator() + + if equalityOp != nil { + return v.doVisitEqualityOperator(ctx, scope) + } + + inOp := ctx.InOperator() + + if inOp != nil { + return v.doVisitInOperator(ctx, scope) + } + + logicalAndOp := ctx.LogicalAndOperator() + + if logicalAndOp != nil { + return v.doVisitLogicalOperator(ctx, scope) + } + + logicalOrOp := ctx.LogicalOrOperator() + + if logicalOrOp != nil { + return v.doVisitLogicalOperator(ctx, scope) + } + variable := ctx.Variable() if variable != nil { @@ -1255,54 +1360,12 @@ func (v *visitor) doVisitExpression(ctx *fql.ExpressionContext, scope *scope) (c return v.doVisitObjectLiteral(obj.(*fql.ObjectLiteralContext), scope) } - funCall := ctx.FunctionCallExpression() - - if funCall != nil { - return v.doVisitFunctionCallExpression(funCall.(*fql.FunctionCallExpressionContext), scope) - } - - member := ctx.MemberExpression() - - if member != nil { - return v.doVisitMemberExpression(member.(*fql.MemberExpressionContext), scope) - } - none := ctx.NoneLiteral() if none != nil { return v.doVisitNoneLiteral(none.(*fql.NoneLiteralContext)) } - arrOp := ctx.ArrayOperator() - - if arrOp != nil { - return v.doVisitArrayOperator(ctx, scope) - } - - inOp := ctx.InOperator() - - if inOp != nil { - return v.doVisitInOperator(ctx, scope) - } - - equalityOp := ctx.EqualityOperator() - - if equalityOp != nil { - return v.doVisitEqualityOperator(ctx, scope) - } - - logicalOp := ctx.LogicalOperator() - - if logicalOp != nil { - return v.doVisitLogicalOperator(ctx, scope) - } - - mathOp := ctx.MathOperator() - - if mathOp != nil { - return v.doVisitMathOperator(ctx, scope) - } - questionCtx := ctx.QuestionMark() if questionCtx != nil { diff --git a/pkg/html/dynamic/document.go b/pkg/drivers/cdp/document.go similarity index 88% rename from pkg/html/dynamic/document.go rename to pkg/drivers/cdp/document.go index 34264e80..7fcde532 100644 --- a/pkg/html/dynamic/document.go +++ b/pkg/drivers/cdp/document.go @@ -1,4 +1,4 @@ -package dynamic +package cdp import ( "context" @@ -8,8 +8,8 @@ import ( "sync" "time" - "github.com/MontFerret/ferret/pkg/html/dynamic/eval" - "github.com/MontFerret/ferret/pkg/html/dynamic/events" + "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" + "github.com/MontFerret/ferret/pkg/drivers/cdp/events" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/logging" "github.com/MontFerret/ferret/pkg/runtime/values" @@ -24,16 +24,6 @@ import ( const BlankPageURL = "about:blank" type ( - ScreenshotFormat string - ScreenshotArgs struct { - X float64 - Y float64 - Width float64 - Height float64 - Format ScreenshotFormat - Quality int - } - HTMLDocument struct { sync.Mutex logger *zerolog.Logger @@ -45,11 +35,6 @@ type ( } ) -const ( - ScreenshotFormatPNG ScreenshotFormat = "png" - ScreenshotFormatJPEG ScreenshotFormat = "jpeg" -) - func handleLoadError(logger *zerolog.Logger, client *cdp.Client) { err := client.Page.Close(context.Background()) @@ -58,12 +43,6 @@ func handleLoadError(logger *zerolog.Logger, client *cdp.Client) { } } -func IsScreenshotFormatValid(format string) bool { - value := ScreenshotFormat(format) - - return value == ScreenshotFormatPNG || value == ScreenshotFormatJPEG -} - func LoadHTMLDocument( ctx context.Context, conn *rpcc.Conn, @@ -390,6 +369,13 @@ func (doc *HTMLDocument) CountBySelector(selector values.String) values.Int { return doc.element.CountBySelector(selector) } +func (doc *HTMLDocument) ExistsBySelector(selector values.String) values.Boolean { + doc.Lock() + defer doc.Unlock() + + return doc.element.ExistsBySelector(selector) +} + func (doc *HTMLDocument) ClickBySelector(selector values.String) (values.Boolean, error) { res, err := eval.Eval( doc.client, @@ -806,23 +792,71 @@ func (doc *HTMLDocument) NavigateForward(skip values.Int, timeout values.Int) (v return values.True, nil } -func (doc *HTMLDocument) PrintToPDF(params *page.PrintToPDFArgs) (core.Value, error) { +func (doc *HTMLDocument) PrintToPDF(params values.HTMLPDFParams) (values.Binary, error) { ctx := context.Background() - reply, err := doc.client.Page.PrintToPDF(ctx, params) + args := page.NewPrintToPDFArgs() + args. + SetLandscape(bool(params.Landscape)). + SetDisplayHeaderFooter(bool(params.DisplayHeaderFooter)). + SetPrintBackground(bool(params.PrintBackground)). + SetIgnoreInvalidPageRanges(bool(params.IgnoreInvalidPageRanges)). + SetPreferCSSPageSize(bool(params.PreferCSSPageSize)) + + if params.Scale > 0 { + args.SetScale(float64(params.Scale)) + } + + if params.PaperWidth > 0 { + args.SetPaperWidth(float64(params.PaperWidth)) + } + + if params.PaperHeight > 0 { + args.SetPaperHeight(float64(params.PaperHeight)) + } + + if params.MarginTop > 0 { + args.SetMarginTop(float64(params.MarginTop)) + } + + if params.MarginBottom > 0 { + args.SetMarginBottom(float64(params.MarginBottom)) + } + + if params.MarginRight > 0 { + args.SetMarginRight(float64(params.MarginRight)) + } + + if params.MarginLeft > 0 { + args.SetMarginLeft(float64(params.MarginLeft)) + } + + if params.PageRanges != values.EmptyString { + args.SetPageRanges(string(params.PageRanges)) + } + + if params.HeaderTemplate != values.EmptyString { + args.SetHeaderTemplate(string(params.HeaderTemplate)) + } + + if params.FooterTemplate != values.EmptyString { + args.SetFooterTemplate(string(params.FooterTemplate)) + } + + reply, err := doc.client.Page.PrintToPDF(ctx, args) if err != nil { - return values.None, err + return values.NewBinary([]byte{}), err } return values.NewBinary(reply.Data), nil } -func (doc *HTMLDocument) CaptureScreenshot(params *ScreenshotArgs) (core.Value, error) { +func (doc *HTMLDocument) CaptureScreenshot(params values.HTMLScreenshotParams) (values.Binary, error) { ctx := context.Background() metrics, err := doc.client.Page.GetLayoutMetrics(ctx) - if params.Format == ScreenshotFormatJPEG && params.Quality < 0 && params.Quality > 100 { + if params.Format == values.HTMLScreenshotFormatJPEG && params.Quality < 0 && params.Quality > 100 { params.Quality = 100 } @@ -835,32 +869,33 @@ func (doc *HTMLDocument) CaptureScreenshot(params *ScreenshotArgs) (core.Value, } if params.Width <= 0 { - params.Width = float64(metrics.LayoutViewport.ClientWidth) - params.X + params.Width = values.Float(metrics.LayoutViewport.ClientWidth) - params.X } if params.Height <= 0 { - params.Height = float64(metrics.LayoutViewport.ClientHeight) - params.Y + params.Height = values.Float(metrics.LayoutViewport.ClientHeight) - params.Y } clip := page.Viewport{ - X: params.X, - Y: params.Y, - Width: params.Width, - Height: params.Height, + X: float64(params.X), + Y: float64(params.Y), + Width: float64(params.Width), + Height: float64(params.Height), Scale: 1.0, } format := string(params.Format) - screenshotArgs := page.CaptureScreenshotArgs{ + quality := int(params.Quality) + args := page.CaptureScreenshotArgs{ Format: &format, - Quality: ¶ms.Quality, + Quality: &quality, Clip: &clip, } - reply, err := doc.client.Page.CaptureScreenshot(ctx, &screenshotArgs) + reply, err := doc.client.Page.CaptureScreenshot(ctx, &args) if err != nil { - return values.None, err + return values.NewBinary([]byte{}), err } return values.NewBinary(reply.Data), nil diff --git a/pkg/html/dynamic/driver.go b/pkg/drivers/cdp/driver.go similarity index 81% rename from pkg/html/dynamic/driver.go rename to pkg/drivers/cdp/driver.go index 0ac5e18f..6689d395 100644 --- a/pkg/html/dynamic/driver.go +++ b/pkg/drivers/cdp/driver.go @@ -1,11 +1,10 @@ -package dynamic +package cdp import ( "context" - "github.com/MontFerret/ferret/pkg/runtime/core" "sync" - "github.com/MontFerret/ferret/pkg/html/common" + "github.com/MontFerret/ferret/pkg/drivers/common" "github.com/MontFerret/ferret/pkg/runtime/logging" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/mafredri/cdp" @@ -18,49 +17,25 @@ import ( "github.com/pkg/errors" ) -type ( - ctxKey struct{} - - Driver struct { - sync.Mutex - dev *devtool.DevTools - conn *rpcc.Conn - client *cdp.Client - session *session.Manager - contextID target.BrowserContextID - options *Options - } -) - -func WithContext(ctx context.Context, drv *Driver) context.Context { - return context.WithValue( - ctx, - ctxKey{}, - drv, - ) -} - -func FromContext(ctx context.Context) (*Driver, error) { - val := ctx.Value(ctxKey{}) - - drv, ok := val.(*Driver) - - if !ok { - return nil, core.Error(core.ErrNotFound, "dynamic HTML Driver") - } - - return drv, nil +type Driver struct { + sync.Mutex + dev *devtool.DevTools + conn *rpcc.Conn + client *cdp.Client + session *session.Manager + contextID target.BrowserContextID + options *Options } func NewDriver(opts ...Option) *Driver { drv := new(Driver) drv.options = newOptions(opts) - drv.dev = devtool.New(drv.options.cdp) + drv.dev = devtool.New(drv.options.address) return drv } -func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (values.HTMLNode, error) { +func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (values.DHTMLDocument, error) { logger := logging.FromContext(ctx) err := drv.init(ctx) diff --git a/pkg/html/dynamic/element.go b/pkg/drivers/cdp/element.go similarity index 96% rename from pkg/html/dynamic/element.go rename to pkg/drivers/cdp/element.go index a02d5461..1fa3583c 100644 --- a/pkg/html/dynamic/element.go +++ b/pkg/drivers/cdp/element.go @@ -1,4 +1,4 @@ -package dynamic +package cdp import ( "context" @@ -11,9 +11,9 @@ import ( "sync" "time" - "github.com/MontFerret/ferret/pkg/html/common" - "github.com/MontFerret/ferret/pkg/html/dynamic/eval" - "github.com/MontFerret/ferret/pkg/html/dynamic/events" + "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" + "github.com/MontFerret/ferret/pkg/drivers/cdp/events" + "github.com/MontFerret/ferret/pkg/drivers/common" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/mafredri/cdp" @@ -679,6 +679,33 @@ func (el *HTMLElement) CountBySelector(selector values.String) values.Int { return values.NewInt(len(res.NodeIDs)) } +func (el *HTMLElement) ExistsBySelector(selector values.String) values.Boolean { + if !el.IsConnected() { + return values.False + } + + ctx, cancel := contextWithTimeout() + defer cancel() + + // TODO: Can we use RemoteObjectID or BackendID instead of NodeId? + selectorArgs := dom.NewQuerySelectorArgs(el.id.nodeID, selector.String()) + res, err := el.client.DOM.QuerySelector(ctx, selectorArgs) + + if err != nil { + el.logError(err). + Str("selector", selector.String()). + Msg("failed to retrieve nodes by selector") + + return values.False + } + + if res.NodeID == 0 { + return values.False + } + + return values.True +} + func (el *HTMLElement) WaitForClass(class values.String, timeout values.Int) error { task := events.NewWaitTask( func() (core.Value, error) { diff --git a/pkg/html/dynamic/eval/eval.go b/pkg/drivers/cdp/eval/eval.go similarity index 100% rename from pkg/html/dynamic/eval/eval.go rename to pkg/drivers/cdp/eval/eval.go diff --git a/pkg/html/dynamic/events/broker.go b/pkg/drivers/cdp/events/broker.go similarity index 100% rename from pkg/html/dynamic/events/broker.go rename to pkg/drivers/cdp/events/broker.go diff --git a/pkg/html/dynamic/events/broker_test.go b/pkg/drivers/cdp/events/broker_test.go similarity index 99% rename from pkg/html/dynamic/events/broker_test.go rename to pkg/drivers/cdp/events/broker_test.go index 25917463..7c03c1ff 100644 --- a/pkg/html/dynamic/events/broker_test.go +++ b/pkg/drivers/cdp/events/broker_test.go @@ -1,7 +1,7 @@ package events_test import ( - "github.com/MontFerret/ferret/pkg/html/dynamic/events" + "github.com/MontFerret/ferret/pkg/drivers/cdp/events" "github.com/mafredri/cdp/protocol/dom" "github.com/mafredri/cdp/protocol/page" . "github.com/smartystreets/goconvey/convey" diff --git a/pkg/html/dynamic/events/dispatch.go b/pkg/drivers/cdp/events/dispatch.go similarity index 95% rename from pkg/html/dynamic/events/dispatch.go rename to pkg/drivers/cdp/events/dispatch.go index fa3c1ed9..1546e0c0 100644 --- a/pkg/html/dynamic/events/dispatch.go +++ b/pkg/drivers/cdp/events/dispatch.go @@ -3,7 +3,7 @@ package events import ( "context" "fmt" - "github.com/MontFerret/ferret/pkg/html/dynamic/eval" + "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/mafredri/cdp" "github.com/mafredri/cdp/protocol/runtime" diff --git a/pkg/html/dynamic/events/wait.go b/pkg/drivers/cdp/events/wait.go similarity index 96% rename from pkg/html/dynamic/events/wait.go rename to pkg/drivers/cdp/events/wait.go index 947131c2..94d7c4ce 100644 --- a/pkg/html/dynamic/events/wait.go +++ b/pkg/drivers/cdp/events/wait.go @@ -1,7 +1,7 @@ package events import ( - "github.com/MontFerret/ferret/pkg/html/dynamic/eval" + "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/mafredri/cdp" diff --git a/pkg/html/dynamic/helpers.go b/pkg/drivers/cdp/helpers.go similarity index 97% rename from pkg/html/dynamic/helpers.go rename to pkg/drivers/cdp/helpers.go index 300371cd..985c011f 100644 --- a/pkg/html/dynamic/helpers.go +++ b/pkg/drivers/cdp/helpers.go @@ -1,12 +1,12 @@ -package dynamic +package cdp import ( "bytes" "context" "errors" - "github.com/MontFerret/ferret/pkg/html/common" - "github.com/MontFerret/ferret/pkg/html/dynamic/eval" - "github.com/MontFerret/ferret/pkg/html/dynamic/events" + "github.com/MontFerret/ferret/pkg/drivers/cdp/eval" + "github.com/MontFerret/ferret/pkg/drivers/cdp/events" + "github.com/MontFerret/ferret/pkg/drivers/common" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/PuerkitoBio/goquery" "github.com/mafredri/cdp" diff --git a/pkg/html/dynamic/options.go b/pkg/drivers/cdp/options.go similarity index 72% rename from pkg/html/dynamic/options.go rename to pkg/drivers/cdp/options.go index bb93e6a9..6f033243 100644 --- a/pkg/html/dynamic/options.go +++ b/pkg/drivers/cdp/options.go @@ -1,18 +1,20 @@ -package dynamic +package cdp type ( Options struct { proxy string userAgent string - cdp string + address string } Option func(opts *Options) ) +const DefaultAddress = "http://127.0.0.1:9222" + func newOptions(setters []Option) *Options { opts := new(Options) - opts.cdp = "http://127.0.0.1:9222" + opts.address = DefaultAddress for _, setter := range setters { setter(opts) @@ -21,9 +23,9 @@ func newOptions(setters []Option) *Options { return opts } -func WithCDP(address string) Option { +func WithAddress(address string) Option { return func(opts *Options) { - opts.cdp = address + opts.address = address } } diff --git a/pkg/html/common/attrs.go b/pkg/drivers/common/attrs.go similarity index 100% rename from pkg/html/common/attrs.go rename to pkg/drivers/common/attrs.go diff --git a/pkg/html/common/lazy.go b/pkg/drivers/common/lazy.go similarity index 100% rename from pkg/html/common/lazy.go rename to pkg/drivers/common/lazy.go diff --git a/pkg/html/common/types.go b/pkg/drivers/common/types.go similarity index 100% rename from pkg/html/common/types.go rename to pkg/drivers/common/types.go diff --git a/pkg/html/common/ua.go b/pkg/drivers/common/ua.go similarity index 100% rename from pkg/html/common/ua.go rename to pkg/drivers/common/ua.go diff --git a/pkg/drivers/driver.go b/pkg/drivers/driver.go new file mode 100644 index 00000000..b7fe5cdd --- /dev/null +++ b/pkg/drivers/driver.go @@ -0,0 +1,65 @@ +package drivers + +import ( + "context" + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" + "io" +) + +type ( + staticCtxKey struct{} + + dynamicCtxKey struct{} + + Static interface { + io.Closer + GetDocument(ctx context.Context, url values.String) (values.HTMLDocument, error) + ParseDocument(ctx context.Context, str values.String) (values.HTMLDocument, error) + } + + Dynamic interface { + io.Closer + GetDocument(ctx context.Context, url values.String) (values.DHTMLDocument, error) + } +) + +func StaticFrom(ctx context.Context) (Static, error) { + val := ctx.Value(staticCtxKey{}) + + drv, ok := val.(Static) + + if !ok { + return nil, core.Error(core.ErrNotFound, "HTML Driver") + } + + return drv, nil +} + +func DynamicFrom(ctx context.Context) (Dynamic, error) { + val := ctx.Value(dynamicCtxKey{}) + + drv, ok := val.(Dynamic) + + if !ok { + return nil, core.Error(core.ErrNotFound, "DHTML Driver") + } + + return drv, nil +} + +func WithStatic(ctx context.Context, drv Static) context.Context { + return context.WithValue( + ctx, + staticCtxKey{}, + drv, + ) +} + +func WithDynamic(ctx context.Context, drv Dynamic) context.Context { + return context.WithValue( + ctx, + dynamicCtxKey{}, + drv, + ) +} diff --git a/pkg/html/static/document.go b/pkg/drivers/http/document.go similarity index 98% rename from pkg/html/static/document.go rename to pkg/drivers/http/document.go index bd315ddf..7f6fad7b 100644 --- a/pkg/html/static/document.go +++ b/pkg/drivers/http/document.go @@ -1,4 +1,4 @@ -package static +package http import ( "github.com/MontFerret/ferret/pkg/runtime/core" diff --git a/pkg/html/static/document_test.go b/pkg/drivers/http/document_test.go similarity index 99% rename from pkg/html/static/document_test.go rename to pkg/drivers/http/document_test.go index b7392d67..b4cd5976 100644 --- a/pkg/html/static/document_test.go +++ b/pkg/drivers/http/document_test.go @@ -1,8 +1,8 @@ -package static_test +package http_test import ( "bytes" - "github.com/MontFerret/ferret/pkg/html/static" + "github.com/MontFerret/ferret/pkg/drivers/http" "github.com/PuerkitoBio/goquery" . "github.com/smartystreets/goconvey/convey" "testing" @@ -228,7 +228,7 @@ func TestDocument(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Selection) + el, err := http.NewHTMLElement(doc.Selection) So(err, ShouldBeNil) diff --git a/pkg/html/static/driver.go b/pkg/drivers/http/driver.go similarity index 78% rename from pkg/html/static/driver.go rename to pkg/drivers/http/driver.go index 86fa669f..9974ed27 100644 --- a/pkg/html/static/driver.go +++ b/pkg/drivers/http/driver.go @@ -1,13 +1,13 @@ -package static +package http import ( "bytes" "context" - "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/logging" "net/http" "net/url" - "github.com/MontFerret/ferret/pkg/html/common" + "github.com/MontFerret/ferret/pkg/drivers/common" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/PuerkitoBio/goquery" "github.com/corpix/uarand" @@ -15,33 +15,9 @@ import ( "github.com/sethgrid/pester" ) -type ( - ctxKey struct{} - - Driver struct { - client *pester.Client - options *Options - } -) - -func WithContext(ctx context.Context, drv *Driver) context.Context { - return context.WithValue( - ctx, - ctxKey{}, - drv, - ) -} - -func FromContext(ctx context.Context) (*Driver, error) { - val := ctx.Value(ctxKey{}) - - drv, ok := val.(*Driver) - - if !ok { - return nil, core.Error(core.ErrNotFound, "static HTML Driver") - } - - return drv, nil +type Driver struct { + client *pester.Client + options *Options } func NewDriver(opts ...Option) *Driver { @@ -80,7 +56,7 @@ func newClientWithProxy(options *Options) (*http.Client, error) { return &http.Client{Transport: tr}, nil } -func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (values.HTMLNode, error) { +func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (values.HTMLDocument, error) { u := targetURL.String() req, err := http.NewRequest(http.MethodGet, u, nil) @@ -97,6 +73,12 @@ func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (va ua := common.GetUserAgent(drv.options.userAgent) + logger := logging.FromContext(ctx) + logger. + Debug(). + Str("user-agent", ua). + Msg("using User-Agent") + // use custom user agent if ua != "" { req.Header.Set("User-Agent", uarand.GetRandom()) @@ -119,7 +101,7 @@ func (drv *Driver) GetDocument(ctx context.Context, targetURL values.String) (va return NewHTMLDocument(u, doc) } -func (drv *Driver) ParseDocument(_ context.Context, str values.String) (values.HTMLNode, error) { +func (drv *Driver) ParseDocument(_ context.Context, str values.String) (values.HTMLDocument, error) { buf := bytes.NewBuffer([]byte(str)) doc, err := goquery.NewDocumentFromReader(buf) diff --git a/pkg/html/static/element.go b/pkg/drivers/http/element.go similarity index 95% rename from pkg/html/static/element.go rename to pkg/drivers/http/element.go index 79ecd311..a1ea4f21 100644 --- a/pkg/html/static/element.go +++ b/pkg/drivers/http/element.go @@ -1,10 +1,10 @@ -package static +package http import ( "encoding/json" "hash/fnv" - "github.com/MontFerret/ferret/pkg/html/common" + "github.com/MontFerret/ferret/pkg/drivers/common" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/PuerkitoBio/goquery" @@ -248,6 +248,16 @@ func (el *HTMLElement) CountBySelector(selector values.String) values.Int { return values.NewInt(selection.Size()) } +func (el *HTMLElement) ExistsBySelector(selector values.String) values.Boolean { + selection := el.selection.Closest(selector.String()) + + if selection == nil { + return values.False + } + + return values.True +} + func (el *HTMLElement) parseAttrs() *values.Object { obj := values.NewObject() diff --git a/pkg/html/static/element_test.go b/pkg/drivers/http/element_test.go similarity index 97% rename from pkg/html/static/element_test.go rename to pkg/drivers/http/element_test.go index c73d760e..a5c18633 100644 --- a/pkg/html/static/element_test.go +++ b/pkg/drivers/http/element_test.go @@ -1,8 +1,8 @@ -package static_test +package http_test import ( "bytes" - "github.com/MontFerret/ferret/pkg/html/static" + "github.com/MontFerret/ferret/pkg/drivers/http" "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/PuerkitoBio/goquery" . "github.com/smartystreets/goconvey/convey" @@ -251,7 +251,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("body")) + el, err := http.NewHTMLElement(doc.Find("body")) So(err, ShouldBeNil) @@ -267,7 +267,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("body")) + el, err := http.NewHTMLElement(doc.Find("body")) So(err, ShouldBeNil) @@ -291,7 +291,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("body")) + el, err := http.NewHTMLElement(doc.Find("body")) So(err, ShouldBeNil) @@ -316,7 +316,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("#q")) + el, err := http.NewHTMLElement(doc.Find("#q")) So(err, ShouldBeNil) @@ -343,7 +343,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("h2")) + el, err := http.NewHTMLElement(doc.Find("h2")) So(err, ShouldBeNil) @@ -370,7 +370,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Find("#content")) + el, err := http.NewHTMLElement(doc.Find("#content")) So(err, ShouldBeNil) @@ -386,7 +386,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Selection) + el, err := http.NewHTMLElement(doc.Selection) So(err, ShouldBeNil) @@ -408,7 +408,7 @@ func TestElement(t *testing.T) { So(err, ShouldBeNil) - el, err := static.NewHTMLElement(doc.Selection) + el, err := http.NewHTMLElement(doc.Selection) So(err, ShouldBeNil) diff --git a/pkg/html/static/options.go b/pkg/drivers/http/options.go similarity index 96% rename from pkg/html/static/options.go rename to pkg/drivers/http/options.go index 3f2fa563..fd951073 100644 --- a/pkg/html/static/options.go +++ b/pkg/drivers/http/options.go @@ -1,11 +1,12 @@ -package static +package http import ( "github.com/sethgrid/pester" ) type ( - Option func(opts *Options) + Option func(opts *Options) + Options struct { backoff pester.BackoffStrategy maxRetries int diff --git a/pkg/html/driver.go b/pkg/html/driver.go deleted file mode 100644 index 044d10c5..00000000 --- a/pkg/html/driver.go +++ /dev/null @@ -1,41 +0,0 @@ -package html - -import ( - "context" - "fmt" - "github.com/MontFerret/ferret/pkg/html/dynamic" - "github.com/MontFerret/ferret/pkg/html/static" - "github.com/MontFerret/ferret/pkg/runtime/core" - "github.com/MontFerret/ferret/pkg/runtime/values" -) - -type DriverName string - -const ( - Dynamic DriverName = "dynamic" - Static DriverName = "static" -) - -type Driver interface { - GetDocument(ctx context.Context, url values.String) (values.HTMLNode, error) - Close() error -} - -func FromContext(ctx context.Context, name DriverName) (Driver, error) { - switch name { - case Dynamic: - return dynamic.FromContext(ctx) - case Static: - return static.FromContext(ctx) - default: - return nil, core.Error(core.ErrInvalidArgument, fmt.Sprintf("%s driver", name)) - } -} - -func WithDynamicDriver(ctx context.Context, opts ...dynamic.Option) context.Context { - return dynamic.WithContext(ctx, dynamic.NewDriver(opts...)) -} - -func WithStaticDriver(ctx context.Context, opts ...static.Option) context.Context { - return static.WithContext(ctx, static.NewDriver(opts...)) -} diff --git a/pkg/parser/antlr/FqlLexer.g4 b/pkg/parser/antlr/FqlLexer.g4 index ea6bcd55..2ca7be18 100644 --- a/pkg/parser/antlr/FqlLexer.g4 +++ b/pkg/parser/antlr/FqlLexer.g4 @@ -27,13 +27,13 @@ Lte: '<='; Neq: '!='; // Arithmetic operators +Multi: '*'; +Div: '/'; +Mod: '%'; Plus: '+'; Minus: '-'; MinusMinus: '--'; PlusPlus: '++'; -Multi: '*'; -Div: '/'; -Mod: '%'; // Logical operators And: 'AND' | '&&'; diff --git a/pkg/parser/antlr/FqlLexer.tokens b/pkg/parser/antlr/FqlLexer.tokens index bc38f772..15deb142 100644 --- a/pkg/parser/antlr/FqlLexer.tokens +++ b/pkg/parser/antlr/FqlLexer.tokens @@ -18,13 +18,13 @@ Eq=17 Gte=18 Lte=19 Neq=20 -Plus=21 -Minus=22 -MinusMinus=23 -PlusPlus=24 -Multi=25 -Div=26 -Mod=27 +Multi=21 +Div=22 +Mod=23 +Plus=24 +Minus=25 +MinusMinus=26 +PlusPlus=27 And=28 Or=29 Range=30 @@ -76,13 +76,13 @@ FloatLiteral=62 '>='=18 '<='=19 '!='=20 -'+'=21 -'-'=22 -'--'=23 -'++'=24 -'*'=25 -'/'=26 -'%'=27 +'*'=21 +'/'=22 +'%'=23 +'+'=24 +'-'=25 +'--'=26 +'++'=27 '='=31 '?'=32 '!~'=33 diff --git a/pkg/parser/antlr/FqlParser.g4 b/pkg/parser/antlr/FqlParser.g4 index 91560325..cd4cc06a 100644 --- a/pkg/parser/antlr/FqlParser.g4 +++ b/pkg/parser/antlr/FqlParser.g4 @@ -203,8 +203,8 @@ propertyName | stringLiteral ; -expressionSequence - : expression (Comma expression)* +expressionGroup + : OpenParen expression CloseParen ; functionCallExpression @@ -217,13 +217,15 @@ arguments expression : unaryOperator expression - | expression equalityOperator expression - | expression logicalOperator expression - | expression mathOperator expression + | expression multiplicativeOperator expression + | expression additiveOperator expression | functionCallExpression - | OpenParen expressionSequence CloseParen + | expressionGroup | expression arrayOperator (inOperator | equalityOperator) expression | expression inOperator expression + | expression equalityOperator expression + | expression logicalAndOperator expression + | expression logicalOrOperator expression | expression QuestionMark expression? Colon expression | rangeOperator | stringLiteral @@ -264,19 +266,25 @@ equalityOperator | Neq ; -logicalOperator +logicalAndOperator : And - | Or ; -mathOperator - : Plus - | Minus - | Multi +logicalOrOperator + : Or + ; + +multiplicativeOperator + : Multi | Div | Mod ; +additiveOperator + : Plus + | Minus + ; + unaryOperator : Not | Plus diff --git a/pkg/parser/fql/FqlLexer.interp b/pkg/parser/fql/FqlLexer.interp index 0a4038f2..06eed1d4 100644 --- a/pkg/parser/fql/FqlLexer.interp +++ b/pkg/parser/fql/FqlLexer.interp @@ -20,13 +20,13 @@ null '>=' '<=' '!=' +'*' +'/' +'%' '+' '-' '--' '++' -'*' -'/' -'%' null null null @@ -85,13 +85,13 @@ Eq Gte Lte Neq +Multi +Div +Mod Plus Minus MinusMinus PlusPlus -Multi -Div -Mod And Or Range @@ -149,13 +149,13 @@ Eq Gte Lte Neq +Multi +Div +Mod Plus Minus MinusMinus PlusPlus -Multi -Div -Mod And Or Range @@ -208,4 +208,4 @@ mode names: DEFAULT_MODE atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 64, 519, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 148, 10, 2, 12, 2, 14, 2, 151, 11, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 162, 10, 3, 12, 3, 14, 3, 165, 11, 3, 3, 3, 3, 3, 3, 4, 6, 4, 170, 10, 4, 13, 4, 14, 4, 171, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 5, 29, 237, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 5, 30, 243, 10, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 5, 44, 315, 10, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 345, 10, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 5, 56, 395, 10, 56, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 6, 59, 403, 10, 59, 13, 59, 14, 59, 404, 3, 59, 3, 59, 7, 59, 409, 10, 59, 12, 59, 14, 59, 412, 11, 59, 7, 59, 414, 10, 59, 12, 59, 14, 59, 417, 11, 59, 3, 59, 3, 59, 7, 59, 421, 10, 59, 12, 59, 14, 59, 424, 11, 59, 7, 59, 426, 10, 59, 12, 59, 14, 59, 429, 11, 59, 3, 60, 3, 60, 5, 60, 433, 10, 60, 3, 61, 3, 61, 3, 61, 3, 61, 7, 61, 439, 10, 61, 12, 61, 14, 61, 442, 11, 61, 3, 61, 3, 61, 3, 62, 6, 62, 447, 10, 62, 13, 62, 14, 62, 448, 3, 63, 3, 63, 3, 63, 6, 63, 454, 10, 63, 13, 63, 14, 63, 455, 3, 63, 5, 63, 459, 10, 63, 3, 63, 3, 63, 5, 63, 463, 10, 63, 5, 63, 465, 10, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 7, 65, 472, 10, 65, 12, 65, 14, 65, 475, 11, 65, 5, 65, 477, 10, 65, 3, 66, 3, 66, 5, 66, 481, 10, 66, 3, 66, 6, 66, 484, 10, 66, 13, 66, 14, 66, 485, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 7, 70, 500, 10, 70, 12, 70, 14, 70, 503, 11, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 7, 71, 513, 10, 71, 12, 71, 14, 71, 516, 11, 71, 3, 71, 3, 71, 3, 149, 2, 72, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 49, 97, 50, 99, 51, 101, 52, 103, 53, 105, 54, 107, 55, 109, 56, 111, 57, 113, 58, 115, 59, 117, 60, 119, 61, 121, 62, 123, 63, 125, 64, 127, 2, 129, 2, 131, 2, 133, 2, 135, 2, 137, 2, 139, 2, 141, 2, 3, 2, 13, 5, 2, 12, 12, 15, 15, 8234, 8235, 6, 2, 11, 11, 13, 14, 34, 34, 162, 162, 3, 2, 98, 98, 3, 2, 50, 59, 5, 2, 50, 59, 67, 72, 99, 104, 3, 2, 51, 59, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 67, 92, 99, 124, 4, 2, 36, 36, 94, 94, 4, 2, 41, 41, 94, 94, 2, 543, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2, 99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2, 2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113, 3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 5, 157, 3, 2, 2, 2, 7, 169, 3, 2, 2, 2, 9, 175, 3, 2, 2, 2, 11, 179, 3, 2, 2, 2, 13, 181, 3, 2, 2, 2, 15, 183, 3, 2, 2, 2, 17, 185, 3, 2, 2, 2, 19, 187, 3, 2, 2, 2, 21, 189, 3, 2, 2, 2, 23, 191, 3, 2, 2, 2, 25, 193, 3, 2, 2, 2, 27, 195, 3, 2, 2, 2, 29, 197, 3, 2, 2, 2, 31, 199, 3, 2, 2, 2, 33, 201, 3, 2, 2, 2, 35, 203, 3, 2, 2, 2, 37, 206, 3, 2, 2, 2, 39, 209, 3, 2, 2, 2, 41, 212, 3, 2, 2, 2, 43, 215, 3, 2, 2, 2, 45, 217, 3, 2, 2, 2, 47, 219, 3, 2, 2, 2, 49, 222, 3, 2, 2, 2, 51, 225, 3, 2, 2, 2, 53, 227, 3, 2, 2, 2, 55, 229, 3, 2, 2, 2, 57, 236, 3, 2, 2, 2, 59, 242, 3, 2, 2, 2, 61, 244, 3, 2, 2, 2, 63, 247, 3, 2, 2, 2, 65, 249, 3, 2, 2, 2, 67, 251, 3, 2, 2, 2, 69, 254, 3, 2, 2, 2, 71, 257, 3, 2, 2, 2, 73, 261, 3, 2, 2, 2, 75, 268, 3, 2, 2, 2, 77, 277, 3, 2, 2, 2, 79, 284, 3, 2, 2, 2, 81, 289, 3, 2, 2, 2, 83, 295, 3, 2, 2, 2, 85, 299, 3, 2, 2, 2, 87, 314, 3, 2, 2, 2, 89, 316, 3, 2, 2, 2, 91, 321, 3, 2, 2, 2, 93, 344, 3, 2, 2, 2, 95, 346, 3, 2, 2, 2, 97, 351, 3, 2, 2, 2, 99, 356, 3, 2, 2, 2, 101, 361, 3, 2, 2, 2, 103, 367, 3, 2, 2, 2, 105, 371, 3, 2, 2, 2, 107, 375, 3, 2, 2, 2, 109, 385, 3, 2, 2, 2, 111, 394, 3, 2, 2, 2, 113, 396, 3, 2, 2, 2, 115, 399, 3, 2, 2, 2, 117, 402, 3, 2, 2, 2, 119, 432, 3, 2, 2, 2, 121, 434, 3, 2, 2, 2, 123, 446, 3, 2, 2, 2, 125, 464, 3, 2, 2, 2, 127, 466, 3, 2, 2, 2, 129, 476, 3, 2, 2, 2, 131, 478, 3, 2, 2, 2, 133, 487, 3, 2, 2, 2, 135, 489, 3, 2, 2, 2, 137, 491, 3, 2, 2, 2, 139, 493, 3, 2, 2, 2, 141, 506, 3, 2, 2, 2, 143, 144, 7, 49, 2, 2, 144, 145, 7, 44, 2, 2, 145, 149, 3, 2, 2, 2, 146, 148, 11, 2, 2, 2, 147, 146, 3, 2, 2, 2, 148, 151, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 149, 147, 3, 2, 2, 2, 150, 152, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 152, 153, 7, 44, 2, 2, 153, 154, 7, 49, 2, 2, 154, 155, 3, 2, 2, 2, 155, 156, 8, 2, 2, 2, 156, 4, 3, 2, 2, 2, 157, 158, 7, 49, 2, 2, 158, 159, 7, 49, 2, 2, 159, 163, 3, 2, 2, 2, 160, 162, 10, 2, 2, 2, 161, 160, 3, 2, 2, 2, 162, 165, 3, 2, 2, 2, 163, 161, 3, 2, 2, 2, 163, 164, 3, 2, 2, 2, 164, 166, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 166, 167, 8, 3, 2, 2, 167, 6, 3, 2, 2, 2, 168, 170, 9, 3, 2, 2, 169, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 169, 3, 2, 2, 2, 171, 172, 3, 2, 2, 2, 172, 173, 3, 2, 2, 2, 173, 174, 8, 4, 2, 2, 174, 8, 3, 2, 2, 2, 175, 176, 9, 2, 2, 2, 176, 177, 3, 2, 2, 2, 177, 178, 8, 5, 2, 2, 178, 10, 3, 2, 2, 2, 179, 180, 7, 60, 2, 2, 180, 12, 3, 2, 2, 2, 181, 182, 7, 61, 2, 2, 182, 14, 3, 2, 2, 2, 183, 184, 7, 48, 2, 2, 184, 16, 3, 2, 2, 2, 185, 186, 7, 46, 2, 2, 186, 18, 3, 2, 2, 2, 187, 188, 7, 93, 2, 2, 188, 20, 3, 2, 2, 2, 189, 190, 7, 95, 2, 2, 190, 22, 3, 2, 2, 2, 191, 192, 7, 42, 2, 2, 192, 24, 3, 2, 2, 2, 193, 194, 7, 43, 2, 2, 194, 26, 3, 2, 2, 2, 195, 196, 7, 125, 2, 2, 196, 28, 3, 2, 2, 2, 197, 198, 7, 127, 2, 2, 198, 30, 3, 2, 2, 2, 199, 200, 7, 64, 2, 2, 200, 32, 3, 2, 2, 2, 201, 202, 7, 62, 2, 2, 202, 34, 3, 2, 2, 2, 203, 204, 7, 63, 2, 2, 204, 205, 7, 63, 2, 2, 205, 36, 3, 2, 2, 2, 206, 207, 7, 64, 2, 2, 207, 208, 7, 63, 2, 2, 208, 38, 3, 2, 2, 2, 209, 210, 7, 62, 2, 2, 210, 211, 7, 63, 2, 2, 211, 40, 3, 2, 2, 2, 212, 213, 7, 35, 2, 2, 213, 214, 7, 63, 2, 2, 214, 42, 3, 2, 2, 2, 215, 216, 7, 45, 2, 2, 216, 44, 3, 2, 2, 2, 217, 218, 7, 47, 2, 2, 218, 46, 3, 2, 2, 2, 219, 220, 7, 47, 2, 2, 220, 221, 7, 47, 2, 2, 221, 48, 3, 2, 2, 2, 222, 223, 7, 45, 2, 2, 223, 224, 7, 45, 2, 2, 224, 50, 3, 2, 2, 2, 225, 226, 7, 44, 2, 2, 226, 52, 3, 2, 2, 2, 227, 228, 7, 49, 2, 2, 228, 54, 3, 2, 2, 2, 229, 230, 7, 39, 2, 2, 230, 56, 3, 2, 2, 2, 231, 232, 7, 67, 2, 2, 232, 233, 7, 80, 2, 2, 233, 237, 7, 70, 2, 2, 234, 235, 7, 40, 2, 2, 235, 237, 7, 40, 2, 2, 236, 231, 3, 2, 2, 2, 236, 234, 3, 2, 2, 2, 237, 58, 3, 2, 2, 2, 238, 239, 7, 81, 2, 2, 239, 243, 7, 84, 2, 2, 240, 241, 7, 126, 2, 2, 241, 243, 7, 126, 2, 2, 242, 238, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 60, 3, 2, 2, 2, 244, 245, 5, 15, 8, 2, 245, 246, 5, 15, 8, 2, 246, 62, 3, 2, 2, 2, 247, 248, 7, 63, 2, 2, 248, 64, 3, 2, 2, 2, 249, 250, 7, 65, 2, 2, 250, 66, 3, 2, 2, 2, 251, 252, 7, 35, 2, 2, 252, 253, 7, 128, 2, 2, 253, 68, 3, 2, 2, 2, 254, 255, 7, 63, 2, 2, 255, 256, 7, 128, 2, 2, 256, 70, 3, 2, 2, 2, 257, 258, 7, 72, 2, 2, 258, 259, 7, 81, 2, 2, 259, 260, 7, 84, 2, 2, 260, 72, 3, 2, 2, 2, 261, 262, 7, 84, 2, 2, 262, 263, 7, 71, 2, 2, 263, 264, 7, 86, 2, 2, 264, 265, 7, 87, 2, 2, 265, 266, 7, 84, 2, 2, 266, 267, 7, 80, 2, 2, 267, 74, 3, 2, 2, 2, 268, 269, 7, 70, 2, 2, 269, 270, 7, 75, 2, 2, 270, 271, 7, 85, 2, 2, 271, 272, 7, 86, 2, 2, 272, 273, 7, 75, 2, 2, 273, 274, 7, 80, 2, 2, 274, 275, 7, 69, 2, 2, 275, 276, 7, 86, 2, 2, 276, 76, 3, 2, 2, 2, 277, 278, 7, 72, 2, 2, 278, 279, 7, 75, 2, 2, 279, 280, 7, 78, 2, 2, 280, 281, 7, 86, 2, 2, 281, 282, 7, 71, 2, 2, 282, 283, 7, 84, 2, 2, 283, 78, 3, 2, 2, 2, 284, 285, 7, 85, 2, 2, 285, 286, 7, 81, 2, 2, 286, 287, 7, 84, 2, 2, 287, 288, 7, 86, 2, 2, 288, 80, 3, 2, 2, 2, 289, 290, 7, 78, 2, 2, 290, 291, 7, 75, 2, 2, 291, 292, 7, 79, 2, 2, 292, 293, 7, 75, 2, 2, 293, 294, 7, 86, 2, 2, 294, 82, 3, 2, 2, 2, 295, 296, 7, 78, 2, 2, 296, 297, 7, 71, 2, 2, 297, 298, 7, 86, 2, 2, 298, 84, 3, 2, 2, 2, 299, 300, 7, 69, 2, 2, 300, 301, 7, 81, 2, 2, 301, 302, 7, 78, 2, 2, 302, 303, 7, 78, 2, 2, 303, 304, 7, 71, 2, 2, 304, 305, 7, 69, 2, 2, 305, 306, 7, 86, 2, 2, 306, 86, 3, 2, 2, 2, 307, 308, 7, 67, 2, 2, 308, 309, 7, 85, 2, 2, 309, 315, 7, 69, 2, 2, 310, 311, 7, 70, 2, 2, 311, 312, 7, 71, 2, 2, 312, 313, 7, 85, 2, 2, 313, 315, 7, 69, 2, 2, 314, 307, 3, 2, 2, 2, 314, 310, 3, 2, 2, 2, 315, 88, 3, 2, 2, 2, 316, 317, 7, 80, 2, 2, 317, 318, 7, 81, 2, 2, 318, 319, 7, 80, 2, 2, 319, 320, 7, 71, 2, 2, 320, 90, 3, 2, 2, 2, 321, 322, 7, 80, 2, 2, 322, 323, 7, 87, 2, 2, 323, 324, 7, 78, 2, 2, 324, 325, 7, 78, 2, 2, 325, 92, 3, 2, 2, 2, 326, 327, 7, 86, 2, 2, 327, 328, 7, 84, 2, 2, 328, 329, 7, 87, 2, 2, 329, 345, 7, 71, 2, 2, 330, 331, 7, 118, 2, 2, 331, 332, 7, 116, 2, 2, 332, 333, 7, 119, 2, 2, 333, 345, 7, 103, 2, 2, 334, 335, 7, 72, 2, 2, 335, 336, 7, 67, 2, 2, 336, 337, 7, 78, 2, 2, 337, 338, 7, 85, 2, 2, 338, 345, 7, 71, 2, 2, 339, 340, 7, 104, 2, 2, 340, 341, 7, 99, 2, 2, 341, 342, 7, 110, 2, 2, 342, 343, 7, 117, 2, 2, 343, 345, 7, 103, 2, 2, 344, 326, 3, 2, 2, 2, 344, 330, 3, 2, 2, 2, 344, 334, 3, 2, 2, 2, 344, 339, 3, 2, 2, 2, 345, 94, 3, 2, 2, 2, 346, 347, 7, 75, 2, 2, 347, 348, 7, 80, 2, 2, 348, 349, 7, 86, 2, 2, 349, 350, 7, 81, 2, 2, 350, 96, 3, 2, 2, 2, 351, 352, 7, 77, 2, 2, 352, 353, 7, 71, 2, 2, 353, 354, 7, 71, 2, 2, 354, 355, 7, 82, 2, 2, 355, 98, 3, 2, 2, 2, 356, 357, 7, 89, 2, 2, 357, 358, 7, 75, 2, 2, 358, 359, 7, 86, 2, 2, 359, 360, 7, 74, 2, 2, 360, 100, 3, 2, 2, 2, 361, 362, 7, 69, 2, 2, 362, 363, 7, 81, 2, 2, 363, 364, 7, 87, 2, 2, 364, 365, 7, 80, 2, 2, 365, 366, 7, 86, 2, 2, 366, 102, 3, 2, 2, 2, 367, 368, 7, 67, 2, 2, 368, 369, 7, 78, 2, 2, 369, 370, 7, 78, 2, 2, 370, 104, 3, 2, 2, 2, 371, 372, 7, 67, 2, 2, 372, 373, 7, 80, 2, 2, 373, 374, 7, 91, 2, 2, 374, 106, 3, 2, 2, 2, 375, 376, 7, 67, 2, 2, 376, 377, 7, 73, 2, 2, 377, 378, 7, 73, 2, 2, 378, 379, 7, 84, 2, 2, 379, 380, 7, 71, 2, 2, 380, 381, 7, 73, 2, 2, 381, 382, 7, 67, 2, 2, 382, 383, 7, 86, 2, 2, 383, 384, 7, 71, 2, 2, 384, 108, 3, 2, 2, 2, 385, 386, 7, 78, 2, 2, 386, 387, 7, 75, 2, 2, 387, 388, 7, 77, 2, 2, 388, 389, 7, 71, 2, 2, 389, 110, 3, 2, 2, 2, 390, 391, 7, 80, 2, 2, 391, 392, 7, 81, 2, 2, 392, 395, 7, 86, 2, 2, 393, 395, 7, 35, 2, 2, 394, 390, 3, 2, 2, 2, 394, 393, 3, 2, 2, 2, 395, 112, 3, 2, 2, 2, 396, 397, 7, 75, 2, 2, 397, 398, 7, 80, 2, 2, 398, 114, 3, 2, 2, 2, 399, 400, 7, 66, 2, 2, 400, 116, 3, 2, 2, 2, 401, 403, 5, 133, 67, 2, 402, 401, 3, 2, 2, 2, 403, 404, 3, 2, 2, 2, 404, 402, 3, 2, 2, 2, 404, 405, 3, 2, 2, 2, 405, 415, 3, 2, 2, 2, 406, 410, 5, 135, 68, 2, 407, 409, 5, 117, 59, 2, 408, 407, 3, 2, 2, 2, 409, 412, 3, 2, 2, 2, 410, 408, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 414, 3, 2, 2, 2, 412, 410, 3, 2, 2, 2, 413, 406, 3, 2, 2, 2, 414, 417, 3, 2, 2, 2, 415, 413, 3, 2, 2, 2, 415, 416, 3, 2, 2, 2, 416, 427, 3, 2, 2, 2, 417, 415, 3, 2, 2, 2, 418, 422, 5, 137, 69, 2, 419, 421, 5, 117, 59, 2, 420, 419, 3, 2, 2, 2, 421, 424, 3, 2, 2, 2, 422, 420, 3, 2, 2, 2, 422, 423, 3, 2, 2, 2, 423, 426, 3, 2, 2, 2, 424, 422, 3, 2, 2, 2, 425, 418, 3, 2, 2, 2, 426, 429, 3, 2, 2, 2, 427, 425, 3, 2, 2, 2, 427, 428, 3, 2, 2, 2, 428, 118, 3, 2, 2, 2, 429, 427, 3, 2, 2, 2, 430, 433, 5, 141, 71, 2, 431, 433, 5, 139, 70, 2, 432, 430, 3, 2, 2, 2, 432, 431, 3, 2, 2, 2, 433, 120, 3, 2, 2, 2, 434, 440, 7, 98, 2, 2, 435, 436, 7, 94, 2, 2, 436, 439, 7, 98, 2, 2, 437, 439, 10, 4, 2, 2, 438, 435, 3, 2, 2, 2, 438, 437, 3, 2, 2, 2, 439, 442, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 440, 441, 3, 2, 2, 2, 441, 443, 3, 2, 2, 2, 442, 440, 3, 2, 2, 2, 443, 444, 7, 98, 2, 2, 444, 122, 3, 2, 2, 2, 445, 447, 9, 5, 2, 2, 446, 445, 3, 2, 2, 2, 447, 448, 3, 2, 2, 2, 448, 446, 3, 2, 2, 2, 448, 449, 3, 2, 2, 2, 449, 124, 3, 2, 2, 2, 450, 451, 5, 129, 65, 2, 451, 453, 5, 15, 8, 2, 452, 454, 9, 5, 2, 2, 453, 452, 3, 2, 2, 2, 454, 455, 3, 2, 2, 2, 455, 453, 3, 2, 2, 2, 455, 456, 3, 2, 2, 2, 456, 458, 3, 2, 2, 2, 457, 459, 5, 131, 66, 2, 458, 457, 3, 2, 2, 2, 458, 459, 3, 2, 2, 2, 459, 465, 3, 2, 2, 2, 460, 462, 5, 129, 65, 2, 461, 463, 5, 131, 66, 2, 462, 461, 3, 2, 2, 2, 462, 463, 3, 2, 2, 2, 463, 465, 3, 2, 2, 2, 464, 450, 3, 2, 2, 2, 464, 460, 3, 2, 2, 2, 465, 126, 3, 2, 2, 2, 466, 467, 9, 6, 2, 2, 467, 128, 3, 2, 2, 2, 468, 477, 7, 50, 2, 2, 469, 473, 9, 7, 2, 2, 470, 472, 9, 5, 2, 2, 471, 470, 3, 2, 2, 2, 472, 475, 3, 2, 2, 2, 473, 471, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 477, 3, 2, 2, 2, 475, 473, 3, 2, 2, 2, 476, 468, 3, 2, 2, 2, 476, 469, 3, 2, 2, 2, 477, 130, 3, 2, 2, 2, 478, 480, 9, 8, 2, 2, 479, 481, 9, 9, 2, 2, 480, 479, 3, 2, 2, 2, 480, 481, 3, 2, 2, 2, 481, 483, 3, 2, 2, 2, 482, 484, 9, 5, 2, 2, 483, 482, 3, 2, 2, 2, 484, 485, 3, 2, 2, 2, 485, 483, 3, 2, 2, 2, 485, 486, 3, 2, 2, 2, 486, 132, 3, 2, 2, 2, 487, 488, 9, 10, 2, 2, 488, 134, 3, 2, 2, 2, 489, 490, 7, 97, 2, 2, 490, 136, 3, 2, 2, 2, 491, 492, 4, 50, 59, 2, 492, 138, 3, 2, 2, 2, 493, 501, 7, 36, 2, 2, 494, 495, 7, 94, 2, 2, 495, 500, 11, 2, 2, 2, 496, 497, 7, 36, 2, 2, 497, 500, 7, 36, 2, 2, 498, 500, 10, 11, 2, 2, 499, 494, 3, 2, 2, 2, 499, 496, 3, 2, 2, 2, 499, 498, 3, 2, 2, 2, 500, 503, 3, 2, 2, 2, 501, 499, 3, 2, 2, 2, 501, 502, 3, 2, 2, 2, 502, 504, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 504, 505, 7, 36, 2, 2, 505, 140, 3, 2, 2, 2, 506, 514, 7, 41, 2, 2, 507, 508, 7, 94, 2, 2, 508, 513, 11, 2, 2, 2, 509, 510, 7, 41, 2, 2, 510, 513, 7, 41, 2, 2, 511, 513, 10, 12, 2, 2, 512, 507, 3, 2, 2, 2, 512, 509, 3, 2, 2, 2, 512, 511, 3, 2, 2, 2, 513, 516, 3, 2, 2, 2, 514, 512, 3, 2, 2, 2, 514, 515, 3, 2, 2, 2, 515, 517, 3, 2, 2, 2, 516, 514, 3, 2, 2, 2, 517, 518, 7, 41, 2, 2, 518, 142, 3, 2, 2, 2, 32, 2, 149, 163, 171, 236, 242, 314, 344, 394, 404, 410, 415, 422, 427, 432, 438, 440, 448, 455, 458, 462, 464, 473, 476, 480, 485, 499, 501, 512, 514, 3, 2, 3, 2] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 64, 519, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 4, 57, 9, 57, 4, 58, 9, 58, 4, 59, 9, 59, 4, 60, 9, 60, 4, 61, 9, 61, 4, 62, 9, 62, 4, 63, 9, 63, 4, 64, 9, 64, 4, 65, 9, 65, 4, 66, 9, 66, 4, 67, 9, 67, 4, 68, 9, 68, 4, 69, 9, 69, 4, 70, 9, 70, 4, 71, 9, 71, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 148, 10, 2, 12, 2, 14, 2, 151, 11, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 162, 10, 3, 12, 3, 14, 3, 165, 11, 3, 3, 3, 3, 3, 3, 4, 6, 4, 170, 10, 4, 13, 4, 14, 4, 171, 3, 4, 3, 4, 3, 5, 3, 5, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 5, 29, 237, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 5, 30, 243, 10, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 37, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 3, 44, 5, 44, 315, 10, 44, 3, 45, 3, 45, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 345, 10, 47, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 49, 3, 49, 3, 49, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 3, 50, 3, 50, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 51, 3, 52, 3, 52, 3, 52, 3, 52, 3, 53, 3, 53, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 54, 3, 55, 3, 55, 3, 55, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 3, 56, 5, 56, 395, 10, 56, 3, 57, 3, 57, 3, 57, 3, 58, 3, 58, 3, 59, 6, 59, 403, 10, 59, 13, 59, 14, 59, 404, 3, 59, 3, 59, 7, 59, 409, 10, 59, 12, 59, 14, 59, 412, 11, 59, 7, 59, 414, 10, 59, 12, 59, 14, 59, 417, 11, 59, 3, 59, 3, 59, 7, 59, 421, 10, 59, 12, 59, 14, 59, 424, 11, 59, 7, 59, 426, 10, 59, 12, 59, 14, 59, 429, 11, 59, 3, 60, 3, 60, 5, 60, 433, 10, 60, 3, 61, 3, 61, 3, 61, 3, 61, 7, 61, 439, 10, 61, 12, 61, 14, 61, 442, 11, 61, 3, 61, 3, 61, 3, 62, 6, 62, 447, 10, 62, 13, 62, 14, 62, 448, 3, 63, 3, 63, 3, 63, 6, 63, 454, 10, 63, 13, 63, 14, 63, 455, 3, 63, 5, 63, 459, 10, 63, 3, 63, 3, 63, 5, 63, 463, 10, 63, 5, 63, 465, 10, 63, 3, 64, 3, 64, 3, 65, 3, 65, 3, 65, 7, 65, 472, 10, 65, 12, 65, 14, 65, 475, 11, 65, 5, 65, 477, 10, 65, 3, 66, 3, 66, 5, 66, 481, 10, 66, 3, 66, 6, 66, 484, 10, 66, 13, 66, 14, 66, 485, 3, 67, 3, 67, 3, 68, 3, 68, 3, 69, 3, 69, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 3, 70, 7, 70, 500, 10, 70, 12, 70, 14, 70, 503, 11, 70, 3, 70, 3, 70, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 3, 71, 7, 71, 513, 10, 71, 12, 71, 14, 71, 516, 11, 71, 3, 71, 3, 71, 3, 149, 2, 72, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 17, 10, 19, 11, 21, 12, 23, 13, 25, 14, 27, 15, 29, 16, 31, 17, 33, 18, 35, 19, 37, 20, 39, 21, 41, 22, 43, 23, 45, 24, 47, 25, 49, 26, 51, 27, 53, 28, 55, 29, 57, 30, 59, 31, 61, 32, 63, 33, 65, 34, 67, 35, 69, 36, 71, 37, 73, 38, 75, 39, 77, 40, 79, 41, 81, 42, 83, 43, 85, 44, 87, 45, 89, 46, 91, 47, 93, 48, 95, 49, 97, 50, 99, 51, 101, 52, 103, 53, 105, 54, 107, 55, 109, 56, 111, 57, 113, 58, 115, 59, 117, 60, 119, 61, 121, 62, 123, 63, 125, 64, 127, 2, 129, 2, 131, 2, 133, 2, 135, 2, 137, 2, 139, 2, 141, 2, 3, 2, 13, 5, 2, 12, 12, 15, 15, 8234, 8235, 6, 2, 11, 11, 13, 14, 34, 34, 162, 162, 3, 2, 98, 98, 3, 2, 50, 59, 5, 2, 50, 59, 67, 72, 99, 104, 3, 2, 51, 59, 4, 2, 71, 71, 103, 103, 4, 2, 45, 45, 47, 47, 4, 2, 67, 92, 99, 124, 4, 2, 36, 36, 94, 94, 4, 2, 41, 41, 94, 94, 2, 543, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 2, 17, 3, 2, 2, 2, 2, 19, 3, 2, 2, 2, 2, 21, 3, 2, 2, 2, 2, 23, 3, 2, 2, 2, 2, 25, 3, 2, 2, 2, 2, 27, 3, 2, 2, 2, 2, 29, 3, 2, 2, 2, 2, 31, 3, 2, 2, 2, 2, 33, 3, 2, 2, 2, 2, 35, 3, 2, 2, 2, 2, 37, 3, 2, 2, 2, 2, 39, 3, 2, 2, 2, 2, 41, 3, 2, 2, 2, 2, 43, 3, 2, 2, 2, 2, 45, 3, 2, 2, 2, 2, 47, 3, 2, 2, 2, 2, 49, 3, 2, 2, 2, 2, 51, 3, 2, 2, 2, 2, 53, 3, 2, 2, 2, 2, 55, 3, 2, 2, 2, 2, 57, 3, 2, 2, 2, 2, 59, 3, 2, 2, 2, 2, 61, 3, 2, 2, 2, 2, 63, 3, 2, 2, 2, 2, 65, 3, 2, 2, 2, 2, 67, 3, 2, 2, 2, 2, 69, 3, 2, 2, 2, 2, 71, 3, 2, 2, 2, 2, 73, 3, 2, 2, 2, 2, 75, 3, 2, 2, 2, 2, 77, 3, 2, 2, 2, 2, 79, 3, 2, 2, 2, 2, 81, 3, 2, 2, 2, 2, 83, 3, 2, 2, 2, 2, 85, 3, 2, 2, 2, 2, 87, 3, 2, 2, 2, 2, 89, 3, 2, 2, 2, 2, 91, 3, 2, 2, 2, 2, 93, 3, 2, 2, 2, 2, 95, 3, 2, 2, 2, 2, 97, 3, 2, 2, 2, 2, 99, 3, 2, 2, 2, 2, 101, 3, 2, 2, 2, 2, 103, 3, 2, 2, 2, 2, 105, 3, 2, 2, 2, 2, 107, 3, 2, 2, 2, 2, 109, 3, 2, 2, 2, 2, 111, 3, 2, 2, 2, 2, 113, 3, 2, 2, 2, 2, 115, 3, 2, 2, 2, 2, 117, 3, 2, 2, 2, 2, 119, 3, 2, 2, 2, 2, 121, 3, 2, 2, 2, 2, 123, 3, 2, 2, 2, 2, 125, 3, 2, 2, 2, 3, 143, 3, 2, 2, 2, 5, 157, 3, 2, 2, 2, 7, 169, 3, 2, 2, 2, 9, 175, 3, 2, 2, 2, 11, 179, 3, 2, 2, 2, 13, 181, 3, 2, 2, 2, 15, 183, 3, 2, 2, 2, 17, 185, 3, 2, 2, 2, 19, 187, 3, 2, 2, 2, 21, 189, 3, 2, 2, 2, 23, 191, 3, 2, 2, 2, 25, 193, 3, 2, 2, 2, 27, 195, 3, 2, 2, 2, 29, 197, 3, 2, 2, 2, 31, 199, 3, 2, 2, 2, 33, 201, 3, 2, 2, 2, 35, 203, 3, 2, 2, 2, 37, 206, 3, 2, 2, 2, 39, 209, 3, 2, 2, 2, 41, 212, 3, 2, 2, 2, 43, 215, 3, 2, 2, 2, 45, 217, 3, 2, 2, 2, 47, 219, 3, 2, 2, 2, 49, 221, 3, 2, 2, 2, 51, 223, 3, 2, 2, 2, 53, 225, 3, 2, 2, 2, 55, 228, 3, 2, 2, 2, 57, 236, 3, 2, 2, 2, 59, 242, 3, 2, 2, 2, 61, 244, 3, 2, 2, 2, 63, 247, 3, 2, 2, 2, 65, 249, 3, 2, 2, 2, 67, 251, 3, 2, 2, 2, 69, 254, 3, 2, 2, 2, 71, 257, 3, 2, 2, 2, 73, 261, 3, 2, 2, 2, 75, 268, 3, 2, 2, 2, 77, 277, 3, 2, 2, 2, 79, 284, 3, 2, 2, 2, 81, 289, 3, 2, 2, 2, 83, 295, 3, 2, 2, 2, 85, 299, 3, 2, 2, 2, 87, 314, 3, 2, 2, 2, 89, 316, 3, 2, 2, 2, 91, 321, 3, 2, 2, 2, 93, 344, 3, 2, 2, 2, 95, 346, 3, 2, 2, 2, 97, 351, 3, 2, 2, 2, 99, 356, 3, 2, 2, 2, 101, 361, 3, 2, 2, 2, 103, 367, 3, 2, 2, 2, 105, 371, 3, 2, 2, 2, 107, 375, 3, 2, 2, 2, 109, 385, 3, 2, 2, 2, 111, 394, 3, 2, 2, 2, 113, 396, 3, 2, 2, 2, 115, 399, 3, 2, 2, 2, 117, 402, 3, 2, 2, 2, 119, 432, 3, 2, 2, 2, 121, 434, 3, 2, 2, 2, 123, 446, 3, 2, 2, 2, 125, 464, 3, 2, 2, 2, 127, 466, 3, 2, 2, 2, 129, 476, 3, 2, 2, 2, 131, 478, 3, 2, 2, 2, 133, 487, 3, 2, 2, 2, 135, 489, 3, 2, 2, 2, 137, 491, 3, 2, 2, 2, 139, 493, 3, 2, 2, 2, 141, 506, 3, 2, 2, 2, 143, 144, 7, 49, 2, 2, 144, 145, 7, 44, 2, 2, 145, 149, 3, 2, 2, 2, 146, 148, 11, 2, 2, 2, 147, 146, 3, 2, 2, 2, 148, 151, 3, 2, 2, 2, 149, 150, 3, 2, 2, 2, 149, 147, 3, 2, 2, 2, 150, 152, 3, 2, 2, 2, 151, 149, 3, 2, 2, 2, 152, 153, 7, 44, 2, 2, 153, 154, 7, 49, 2, 2, 154, 155, 3, 2, 2, 2, 155, 156, 8, 2, 2, 2, 156, 4, 3, 2, 2, 2, 157, 158, 7, 49, 2, 2, 158, 159, 7, 49, 2, 2, 159, 163, 3, 2, 2, 2, 160, 162, 10, 2, 2, 2, 161, 160, 3, 2, 2, 2, 162, 165, 3, 2, 2, 2, 163, 161, 3, 2, 2, 2, 163, 164, 3, 2, 2, 2, 164, 166, 3, 2, 2, 2, 165, 163, 3, 2, 2, 2, 166, 167, 8, 3, 2, 2, 167, 6, 3, 2, 2, 2, 168, 170, 9, 3, 2, 2, 169, 168, 3, 2, 2, 2, 170, 171, 3, 2, 2, 2, 171, 169, 3, 2, 2, 2, 171, 172, 3, 2, 2, 2, 172, 173, 3, 2, 2, 2, 173, 174, 8, 4, 2, 2, 174, 8, 3, 2, 2, 2, 175, 176, 9, 2, 2, 2, 176, 177, 3, 2, 2, 2, 177, 178, 8, 5, 2, 2, 178, 10, 3, 2, 2, 2, 179, 180, 7, 60, 2, 2, 180, 12, 3, 2, 2, 2, 181, 182, 7, 61, 2, 2, 182, 14, 3, 2, 2, 2, 183, 184, 7, 48, 2, 2, 184, 16, 3, 2, 2, 2, 185, 186, 7, 46, 2, 2, 186, 18, 3, 2, 2, 2, 187, 188, 7, 93, 2, 2, 188, 20, 3, 2, 2, 2, 189, 190, 7, 95, 2, 2, 190, 22, 3, 2, 2, 2, 191, 192, 7, 42, 2, 2, 192, 24, 3, 2, 2, 2, 193, 194, 7, 43, 2, 2, 194, 26, 3, 2, 2, 2, 195, 196, 7, 125, 2, 2, 196, 28, 3, 2, 2, 2, 197, 198, 7, 127, 2, 2, 198, 30, 3, 2, 2, 2, 199, 200, 7, 64, 2, 2, 200, 32, 3, 2, 2, 2, 201, 202, 7, 62, 2, 2, 202, 34, 3, 2, 2, 2, 203, 204, 7, 63, 2, 2, 204, 205, 7, 63, 2, 2, 205, 36, 3, 2, 2, 2, 206, 207, 7, 64, 2, 2, 207, 208, 7, 63, 2, 2, 208, 38, 3, 2, 2, 2, 209, 210, 7, 62, 2, 2, 210, 211, 7, 63, 2, 2, 211, 40, 3, 2, 2, 2, 212, 213, 7, 35, 2, 2, 213, 214, 7, 63, 2, 2, 214, 42, 3, 2, 2, 2, 215, 216, 7, 44, 2, 2, 216, 44, 3, 2, 2, 2, 217, 218, 7, 49, 2, 2, 218, 46, 3, 2, 2, 2, 219, 220, 7, 39, 2, 2, 220, 48, 3, 2, 2, 2, 221, 222, 7, 45, 2, 2, 222, 50, 3, 2, 2, 2, 223, 224, 7, 47, 2, 2, 224, 52, 3, 2, 2, 2, 225, 226, 7, 47, 2, 2, 226, 227, 7, 47, 2, 2, 227, 54, 3, 2, 2, 2, 228, 229, 7, 45, 2, 2, 229, 230, 7, 45, 2, 2, 230, 56, 3, 2, 2, 2, 231, 232, 7, 67, 2, 2, 232, 233, 7, 80, 2, 2, 233, 237, 7, 70, 2, 2, 234, 235, 7, 40, 2, 2, 235, 237, 7, 40, 2, 2, 236, 231, 3, 2, 2, 2, 236, 234, 3, 2, 2, 2, 237, 58, 3, 2, 2, 2, 238, 239, 7, 81, 2, 2, 239, 243, 7, 84, 2, 2, 240, 241, 7, 126, 2, 2, 241, 243, 7, 126, 2, 2, 242, 238, 3, 2, 2, 2, 242, 240, 3, 2, 2, 2, 243, 60, 3, 2, 2, 2, 244, 245, 5, 15, 8, 2, 245, 246, 5, 15, 8, 2, 246, 62, 3, 2, 2, 2, 247, 248, 7, 63, 2, 2, 248, 64, 3, 2, 2, 2, 249, 250, 7, 65, 2, 2, 250, 66, 3, 2, 2, 2, 251, 252, 7, 35, 2, 2, 252, 253, 7, 128, 2, 2, 253, 68, 3, 2, 2, 2, 254, 255, 7, 63, 2, 2, 255, 256, 7, 128, 2, 2, 256, 70, 3, 2, 2, 2, 257, 258, 7, 72, 2, 2, 258, 259, 7, 81, 2, 2, 259, 260, 7, 84, 2, 2, 260, 72, 3, 2, 2, 2, 261, 262, 7, 84, 2, 2, 262, 263, 7, 71, 2, 2, 263, 264, 7, 86, 2, 2, 264, 265, 7, 87, 2, 2, 265, 266, 7, 84, 2, 2, 266, 267, 7, 80, 2, 2, 267, 74, 3, 2, 2, 2, 268, 269, 7, 70, 2, 2, 269, 270, 7, 75, 2, 2, 270, 271, 7, 85, 2, 2, 271, 272, 7, 86, 2, 2, 272, 273, 7, 75, 2, 2, 273, 274, 7, 80, 2, 2, 274, 275, 7, 69, 2, 2, 275, 276, 7, 86, 2, 2, 276, 76, 3, 2, 2, 2, 277, 278, 7, 72, 2, 2, 278, 279, 7, 75, 2, 2, 279, 280, 7, 78, 2, 2, 280, 281, 7, 86, 2, 2, 281, 282, 7, 71, 2, 2, 282, 283, 7, 84, 2, 2, 283, 78, 3, 2, 2, 2, 284, 285, 7, 85, 2, 2, 285, 286, 7, 81, 2, 2, 286, 287, 7, 84, 2, 2, 287, 288, 7, 86, 2, 2, 288, 80, 3, 2, 2, 2, 289, 290, 7, 78, 2, 2, 290, 291, 7, 75, 2, 2, 291, 292, 7, 79, 2, 2, 292, 293, 7, 75, 2, 2, 293, 294, 7, 86, 2, 2, 294, 82, 3, 2, 2, 2, 295, 296, 7, 78, 2, 2, 296, 297, 7, 71, 2, 2, 297, 298, 7, 86, 2, 2, 298, 84, 3, 2, 2, 2, 299, 300, 7, 69, 2, 2, 300, 301, 7, 81, 2, 2, 301, 302, 7, 78, 2, 2, 302, 303, 7, 78, 2, 2, 303, 304, 7, 71, 2, 2, 304, 305, 7, 69, 2, 2, 305, 306, 7, 86, 2, 2, 306, 86, 3, 2, 2, 2, 307, 308, 7, 67, 2, 2, 308, 309, 7, 85, 2, 2, 309, 315, 7, 69, 2, 2, 310, 311, 7, 70, 2, 2, 311, 312, 7, 71, 2, 2, 312, 313, 7, 85, 2, 2, 313, 315, 7, 69, 2, 2, 314, 307, 3, 2, 2, 2, 314, 310, 3, 2, 2, 2, 315, 88, 3, 2, 2, 2, 316, 317, 7, 80, 2, 2, 317, 318, 7, 81, 2, 2, 318, 319, 7, 80, 2, 2, 319, 320, 7, 71, 2, 2, 320, 90, 3, 2, 2, 2, 321, 322, 7, 80, 2, 2, 322, 323, 7, 87, 2, 2, 323, 324, 7, 78, 2, 2, 324, 325, 7, 78, 2, 2, 325, 92, 3, 2, 2, 2, 326, 327, 7, 86, 2, 2, 327, 328, 7, 84, 2, 2, 328, 329, 7, 87, 2, 2, 329, 345, 7, 71, 2, 2, 330, 331, 7, 118, 2, 2, 331, 332, 7, 116, 2, 2, 332, 333, 7, 119, 2, 2, 333, 345, 7, 103, 2, 2, 334, 335, 7, 72, 2, 2, 335, 336, 7, 67, 2, 2, 336, 337, 7, 78, 2, 2, 337, 338, 7, 85, 2, 2, 338, 345, 7, 71, 2, 2, 339, 340, 7, 104, 2, 2, 340, 341, 7, 99, 2, 2, 341, 342, 7, 110, 2, 2, 342, 343, 7, 117, 2, 2, 343, 345, 7, 103, 2, 2, 344, 326, 3, 2, 2, 2, 344, 330, 3, 2, 2, 2, 344, 334, 3, 2, 2, 2, 344, 339, 3, 2, 2, 2, 345, 94, 3, 2, 2, 2, 346, 347, 7, 75, 2, 2, 347, 348, 7, 80, 2, 2, 348, 349, 7, 86, 2, 2, 349, 350, 7, 81, 2, 2, 350, 96, 3, 2, 2, 2, 351, 352, 7, 77, 2, 2, 352, 353, 7, 71, 2, 2, 353, 354, 7, 71, 2, 2, 354, 355, 7, 82, 2, 2, 355, 98, 3, 2, 2, 2, 356, 357, 7, 89, 2, 2, 357, 358, 7, 75, 2, 2, 358, 359, 7, 86, 2, 2, 359, 360, 7, 74, 2, 2, 360, 100, 3, 2, 2, 2, 361, 362, 7, 69, 2, 2, 362, 363, 7, 81, 2, 2, 363, 364, 7, 87, 2, 2, 364, 365, 7, 80, 2, 2, 365, 366, 7, 86, 2, 2, 366, 102, 3, 2, 2, 2, 367, 368, 7, 67, 2, 2, 368, 369, 7, 78, 2, 2, 369, 370, 7, 78, 2, 2, 370, 104, 3, 2, 2, 2, 371, 372, 7, 67, 2, 2, 372, 373, 7, 80, 2, 2, 373, 374, 7, 91, 2, 2, 374, 106, 3, 2, 2, 2, 375, 376, 7, 67, 2, 2, 376, 377, 7, 73, 2, 2, 377, 378, 7, 73, 2, 2, 378, 379, 7, 84, 2, 2, 379, 380, 7, 71, 2, 2, 380, 381, 7, 73, 2, 2, 381, 382, 7, 67, 2, 2, 382, 383, 7, 86, 2, 2, 383, 384, 7, 71, 2, 2, 384, 108, 3, 2, 2, 2, 385, 386, 7, 78, 2, 2, 386, 387, 7, 75, 2, 2, 387, 388, 7, 77, 2, 2, 388, 389, 7, 71, 2, 2, 389, 110, 3, 2, 2, 2, 390, 391, 7, 80, 2, 2, 391, 392, 7, 81, 2, 2, 392, 395, 7, 86, 2, 2, 393, 395, 7, 35, 2, 2, 394, 390, 3, 2, 2, 2, 394, 393, 3, 2, 2, 2, 395, 112, 3, 2, 2, 2, 396, 397, 7, 75, 2, 2, 397, 398, 7, 80, 2, 2, 398, 114, 3, 2, 2, 2, 399, 400, 7, 66, 2, 2, 400, 116, 3, 2, 2, 2, 401, 403, 5, 133, 67, 2, 402, 401, 3, 2, 2, 2, 403, 404, 3, 2, 2, 2, 404, 402, 3, 2, 2, 2, 404, 405, 3, 2, 2, 2, 405, 415, 3, 2, 2, 2, 406, 410, 5, 135, 68, 2, 407, 409, 5, 117, 59, 2, 408, 407, 3, 2, 2, 2, 409, 412, 3, 2, 2, 2, 410, 408, 3, 2, 2, 2, 410, 411, 3, 2, 2, 2, 411, 414, 3, 2, 2, 2, 412, 410, 3, 2, 2, 2, 413, 406, 3, 2, 2, 2, 414, 417, 3, 2, 2, 2, 415, 413, 3, 2, 2, 2, 415, 416, 3, 2, 2, 2, 416, 427, 3, 2, 2, 2, 417, 415, 3, 2, 2, 2, 418, 422, 5, 137, 69, 2, 419, 421, 5, 117, 59, 2, 420, 419, 3, 2, 2, 2, 421, 424, 3, 2, 2, 2, 422, 420, 3, 2, 2, 2, 422, 423, 3, 2, 2, 2, 423, 426, 3, 2, 2, 2, 424, 422, 3, 2, 2, 2, 425, 418, 3, 2, 2, 2, 426, 429, 3, 2, 2, 2, 427, 425, 3, 2, 2, 2, 427, 428, 3, 2, 2, 2, 428, 118, 3, 2, 2, 2, 429, 427, 3, 2, 2, 2, 430, 433, 5, 141, 71, 2, 431, 433, 5, 139, 70, 2, 432, 430, 3, 2, 2, 2, 432, 431, 3, 2, 2, 2, 433, 120, 3, 2, 2, 2, 434, 440, 7, 98, 2, 2, 435, 436, 7, 94, 2, 2, 436, 439, 7, 98, 2, 2, 437, 439, 10, 4, 2, 2, 438, 435, 3, 2, 2, 2, 438, 437, 3, 2, 2, 2, 439, 442, 3, 2, 2, 2, 440, 438, 3, 2, 2, 2, 440, 441, 3, 2, 2, 2, 441, 443, 3, 2, 2, 2, 442, 440, 3, 2, 2, 2, 443, 444, 7, 98, 2, 2, 444, 122, 3, 2, 2, 2, 445, 447, 9, 5, 2, 2, 446, 445, 3, 2, 2, 2, 447, 448, 3, 2, 2, 2, 448, 446, 3, 2, 2, 2, 448, 449, 3, 2, 2, 2, 449, 124, 3, 2, 2, 2, 450, 451, 5, 129, 65, 2, 451, 453, 5, 15, 8, 2, 452, 454, 9, 5, 2, 2, 453, 452, 3, 2, 2, 2, 454, 455, 3, 2, 2, 2, 455, 453, 3, 2, 2, 2, 455, 456, 3, 2, 2, 2, 456, 458, 3, 2, 2, 2, 457, 459, 5, 131, 66, 2, 458, 457, 3, 2, 2, 2, 458, 459, 3, 2, 2, 2, 459, 465, 3, 2, 2, 2, 460, 462, 5, 129, 65, 2, 461, 463, 5, 131, 66, 2, 462, 461, 3, 2, 2, 2, 462, 463, 3, 2, 2, 2, 463, 465, 3, 2, 2, 2, 464, 450, 3, 2, 2, 2, 464, 460, 3, 2, 2, 2, 465, 126, 3, 2, 2, 2, 466, 467, 9, 6, 2, 2, 467, 128, 3, 2, 2, 2, 468, 477, 7, 50, 2, 2, 469, 473, 9, 7, 2, 2, 470, 472, 9, 5, 2, 2, 471, 470, 3, 2, 2, 2, 472, 475, 3, 2, 2, 2, 473, 471, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 477, 3, 2, 2, 2, 475, 473, 3, 2, 2, 2, 476, 468, 3, 2, 2, 2, 476, 469, 3, 2, 2, 2, 477, 130, 3, 2, 2, 2, 478, 480, 9, 8, 2, 2, 479, 481, 9, 9, 2, 2, 480, 479, 3, 2, 2, 2, 480, 481, 3, 2, 2, 2, 481, 483, 3, 2, 2, 2, 482, 484, 9, 5, 2, 2, 483, 482, 3, 2, 2, 2, 484, 485, 3, 2, 2, 2, 485, 483, 3, 2, 2, 2, 485, 486, 3, 2, 2, 2, 486, 132, 3, 2, 2, 2, 487, 488, 9, 10, 2, 2, 488, 134, 3, 2, 2, 2, 489, 490, 7, 97, 2, 2, 490, 136, 3, 2, 2, 2, 491, 492, 4, 50, 59, 2, 492, 138, 3, 2, 2, 2, 493, 501, 7, 36, 2, 2, 494, 495, 7, 94, 2, 2, 495, 500, 11, 2, 2, 2, 496, 497, 7, 36, 2, 2, 497, 500, 7, 36, 2, 2, 498, 500, 10, 11, 2, 2, 499, 494, 3, 2, 2, 2, 499, 496, 3, 2, 2, 2, 499, 498, 3, 2, 2, 2, 500, 503, 3, 2, 2, 2, 501, 499, 3, 2, 2, 2, 501, 502, 3, 2, 2, 2, 502, 504, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 504, 505, 7, 36, 2, 2, 505, 140, 3, 2, 2, 2, 506, 514, 7, 41, 2, 2, 507, 508, 7, 94, 2, 2, 508, 513, 11, 2, 2, 2, 509, 510, 7, 41, 2, 2, 510, 513, 7, 41, 2, 2, 511, 513, 10, 12, 2, 2, 512, 507, 3, 2, 2, 2, 512, 509, 3, 2, 2, 2, 512, 511, 3, 2, 2, 2, 513, 516, 3, 2, 2, 2, 514, 512, 3, 2, 2, 2, 514, 515, 3, 2, 2, 2, 515, 517, 3, 2, 2, 2, 516, 514, 3, 2, 2, 2, 517, 518, 7, 41, 2, 2, 518, 142, 3, 2, 2, 2, 32, 2, 149, 163, 171, 236, 242, 314, 344, 394, 404, 410, 415, 422, 427, 432, 438, 440, 448, 455, 458, 462, 464, 473, 476, 480, 485, 499, 501, 512, 514, 3, 2, 3, 2] \ No newline at end of file diff --git a/pkg/parser/fql/FqlLexer.tokens b/pkg/parser/fql/FqlLexer.tokens index bc38f772..15deb142 100644 --- a/pkg/parser/fql/FqlLexer.tokens +++ b/pkg/parser/fql/FqlLexer.tokens @@ -18,13 +18,13 @@ Eq=17 Gte=18 Lte=19 Neq=20 -Plus=21 -Minus=22 -MinusMinus=23 -PlusPlus=24 -Multi=25 -Div=26 -Mod=27 +Multi=21 +Div=22 +Mod=23 +Plus=24 +Minus=25 +MinusMinus=26 +PlusPlus=27 And=28 Or=29 Range=30 @@ -76,13 +76,13 @@ FloatLiteral=62 '>='=18 '<='=19 '!='=20 -'+'=21 -'-'=22 -'--'=23 -'++'=24 -'*'=25 -'/'=26 -'%'=27 +'*'=21 +'/'=22 +'%'=23 +'+'=24 +'-'=25 +'--'=26 +'++'=27 '='=31 '?'=32 '!~'=33 diff --git a/pkg/parser/fql/FqlParser.interp b/pkg/parser/fql/FqlParser.interp index 721d74e5..23aa5b67 100644 --- a/pkg/parser/fql/FqlParser.interp +++ b/pkg/parser/fql/FqlParser.interp @@ -20,13 +20,13 @@ null '>=' '<=' '!=' +'*' +'/' +'%' '+' '-' '--' '++' -'*' -'/' -'%' null null null @@ -85,13 +85,13 @@ Eq Gte Lte Neq +Multi +Div +Mod Plus Minus MinusMinus PlusPlus -Multi -Div -Mod And Or Range @@ -171,7 +171,7 @@ memberExpression shorthandPropertyName computedPropertyName propertyName -expressionSequence +expressionGroup functionCallExpression arguments expression @@ -179,10 +179,12 @@ forTernaryExpression arrayOperator inOperator equalityOperator -logicalOperator -mathOperator +logicalAndOperator +logicalOrOperator +multiplicativeOperator +additiveOperator unaryOperator atn: -[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 64, 545, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 3, 2, 3, 2, 3, 3, 7, 3, 112, 10, 3, 12, 3, 14, 3, 115, 11, 3, 3, 3, 3, 3, 3, 4, 3, 4, 5, 4, 121, 10, 4, 3, 5, 3, 5, 5, 5, 125, 10, 5, 3, 6, 3, 6, 5, 6, 129, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 134, 10, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 142, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 148, 10, 7, 3, 7, 3, 7, 3, 7, 7, 7, 153, 10, 7, 12, 7, 14, 7, 156, 11, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 171, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 177, 10, 11, 3, 12, 3, 12, 5, 12, 181, 10, 12, 3, 13, 3, 13, 5, 13, 185, 10, 13, 3, 14, 3, 14, 5, 14, 189, 10, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 5, 16, 198, 10, 16, 3, 17, 3, 17, 5, 17, 202, 10, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 208, 10, 18, 12, 18, 14, 18, 211, 11, 18, 3, 19, 3, 19, 5, 19, 215, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 235, 10, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 7, 22, 244, 10, 22, 12, 22, 14, 22, 247, 11, 22, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 253, 10, 23, 12, 23, 14, 23, 256, 11, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 268, 10, 25, 5, 25, 270, 10, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 5, 27, 292, 10, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 5, 30, 302, 10, 30, 3, 30, 3, 30, 3, 30, 3, 30, 5, 30, 308, 10, 30, 3, 31, 3, 31, 5, 31, 312, 10, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 7, 32, 320, 10, 32, 12, 32, 14, 32, 323, 11, 32, 5, 32, 325, 10, 32, 3, 32, 5, 32, 328, 10, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 6, 38, 344, 10, 38, 13, 38, 14, 38, 345, 3, 38, 7, 38, 349, 10, 38, 12, 38, 14, 38, 352, 11, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 5, 39, 363, 10, 39, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 369, 10, 40, 12, 40, 14, 40, 372, 11, 40, 6, 40, 374, 10, 40, 13, 40, 14, 40, 375, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 383, 10, 40, 12, 40, 14, 40, 386, 11, 40, 7, 40, 388, 10, 40, 12, 40, 14, 40, 391, 11, 40, 3, 40, 3, 40, 3, 40, 7, 40, 396, 10, 40, 12, 40, 14, 40, 399, 11, 40, 7, 40, 401, 10, 40, 12, 40, 14, 40, 404, 11, 40, 5, 40, 406, 10, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 5, 43, 416, 10, 43, 3, 44, 3, 44, 3, 44, 7, 44, 421, 10, 44, 12, 44, 14, 44, 424, 11, 44, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 7, 46, 433, 10, 46, 12, 46, 14, 46, 436, 11, 46, 5, 46, 438, 10, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 462, 10, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 480, 10, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 491, 10, 47, 3, 47, 3, 47, 7, 47, 495, 10, 47, 12, 47, 14, 47, 498, 11, 47, 3, 48, 3, 48, 3, 48, 5, 48, 503, 10, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 528, 10, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 5, 50, 535, 10, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 54, 2, 3, 92, 55, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 2, 9, 3, 2, 61, 62, 3, 2, 46, 47, 4, 2, 46, 46, 53, 54, 3, 2, 17, 22, 3, 2, 30, 31, 4, 2, 23, 24, 27, 29, 4, 2, 23, 24, 56, 57, 2, 575, 2, 108, 3, 2, 2, 2, 4, 113, 3, 2, 2, 2, 6, 120, 3, 2, 2, 2, 8, 124, 3, 2, 2, 2, 10, 141, 3, 2, 2, 2, 12, 143, 3, 2, 2, 2, 14, 159, 3, 2, 2, 2, 16, 161, 3, 2, 2, 2, 18, 170, 3, 2, 2, 2, 20, 176, 3, 2, 2, 2, 22, 180, 3, 2, 2, 2, 24, 184, 3, 2, 2, 2, 26, 188, 3, 2, 2, 2, 28, 190, 3, 2, 2, 2, 30, 193, 3, 2, 2, 2, 32, 201, 3, 2, 2, 2, 34, 203, 3, 2, 2, 2, 36, 212, 3, 2, 2, 2, 38, 234, 3, 2, 2, 2, 40, 236, 3, 2, 2, 2, 42, 240, 3, 2, 2, 2, 44, 248, 3, 2, 2, 2, 46, 257, 3, 2, 2, 2, 48, 269, 3, 2, 2, 2, 50, 271, 3, 2, 2, 2, 52, 291, 3, 2, 2, 2, 54, 293, 3, 2, 2, 2, 56, 296, 3, 2, 2, 2, 58, 301, 3, 2, 2, 2, 60, 309, 3, 2, 2, 2, 62, 315, 3, 2, 2, 2, 64, 331, 3, 2, 2, 2, 66, 333, 3, 2, 2, 2, 68, 335, 3, 2, 2, 2, 70, 337, 3, 2, 2, 2, 72, 339, 3, 2, 2, 2, 74, 341, 3, 2, 2, 2, 76, 362, 3, 2, 2, 2, 78, 405, 3, 2, 2, 2, 80, 407, 3, 2, 2, 2, 82, 409, 3, 2, 2, 2, 84, 415, 3, 2, 2, 2, 86, 417, 3, 2, 2, 2, 88, 425, 3, 2, 2, 2, 90, 428, 3, 2, 2, 2, 92, 461, 3, 2, 2, 2, 94, 527, 3, 2, 2, 2, 96, 529, 3, 2, 2, 2, 98, 534, 3, 2, 2, 2, 100, 536, 3, 2, 2, 2, 102, 538, 3, 2, 2, 2, 104, 540, 3, 2, 2, 2, 106, 542, 3, 2, 2, 2, 108, 109, 5, 4, 3, 2, 109, 3, 3, 2, 2, 2, 110, 112, 5, 6, 4, 2, 111, 110, 3, 2, 2, 2, 112, 115, 3, 2, 2, 2, 113, 111, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 116, 3, 2, 2, 2, 115, 113, 3, 2, 2, 2, 116, 117, 5, 8, 5, 2, 117, 5, 3, 2, 2, 2, 118, 121, 5, 88, 45, 2, 119, 121, 5, 52, 27, 2, 120, 118, 3, 2, 2, 2, 120, 119, 3, 2, 2, 2, 121, 7, 3, 2, 2, 2, 122, 125, 5, 10, 6, 2, 123, 125, 5, 12, 7, 2, 124, 122, 3, 2, 2, 2, 124, 123, 3, 2, 2, 2, 125, 9, 3, 2, 2, 2, 126, 128, 7, 38, 2, 2, 127, 129, 7, 39, 2, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 142, 5, 92, 47, 2, 131, 133, 7, 38, 2, 2, 132, 134, 7, 39, 2, 2, 133, 132, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 135, 3, 2, 2, 2, 135, 136, 7, 13, 2, 2, 136, 137, 5, 12, 7, 2, 137, 138, 7, 14, 2, 2, 138, 142, 3, 2, 2, 2, 139, 140, 7, 38, 2, 2, 140, 142, 5, 94, 48, 2, 141, 126, 3, 2, 2, 2, 141, 131, 3, 2, 2, 2, 141, 139, 3, 2, 2, 2, 142, 11, 3, 2, 2, 2, 143, 144, 7, 37, 2, 2, 144, 147, 5, 14, 8, 2, 145, 146, 7, 10, 2, 2, 146, 148, 5, 16, 9, 2, 147, 145, 3, 2, 2, 2, 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 58, 2, 2, 150, 154, 5, 18, 10, 2, 151, 153, 5, 24, 13, 2, 152, 151, 3, 2, 2, 2, 153, 156, 3, 2, 2, 2, 154, 152, 3, 2, 2, 2, 154, 155, 3, 2, 2, 2, 155, 157, 3, 2, 2, 2, 156, 154, 3, 2, 2, 2, 157, 158, 5, 26, 14, 2, 158, 13, 3, 2, 2, 2, 159, 160, 7, 60, 2, 2, 160, 15, 3, 2, 2, 2, 161, 162, 7, 60, 2, 2, 162, 17, 3, 2, 2, 2, 163, 171, 5, 88, 45, 2, 164, 171, 5, 60, 31, 2, 165, 171, 5, 62, 32, 2, 166, 171, 5, 56, 29, 2, 167, 171, 5, 78, 40, 2, 168, 171, 5, 58, 30, 2, 169, 171, 5, 54, 28, 2, 170, 163, 3, 2, 2, 2, 170, 164, 3, 2, 2, 2, 170, 165, 3, 2, 2, 2, 170, 166, 3, 2, 2, 2, 170, 167, 3, 2, 2, 2, 170, 168, 3, 2, 2, 2, 170, 169, 3, 2, 2, 2, 171, 19, 3, 2, 2, 2, 172, 177, 5, 30, 16, 2, 173, 177, 5, 34, 18, 2, 174, 177, 5, 28, 15, 2, 175, 177, 5, 38, 20, 2, 176, 172, 3, 2, 2, 2, 176, 173, 3, 2, 2, 2, 176, 174, 3, 2, 2, 2, 176, 175, 3, 2, 2, 2, 177, 21, 3, 2, 2, 2, 178, 181, 5, 52, 27, 2, 179, 181, 5, 88, 45, 2, 180, 178, 3, 2, 2, 2, 180, 179, 3, 2, 2, 2, 181, 23, 3, 2, 2, 2, 182, 185, 5, 22, 12, 2, 183, 185, 5, 20, 11, 2, 184, 182, 3, 2, 2, 2, 184, 183, 3, 2, 2, 2, 185, 25, 3, 2, 2, 2, 186, 189, 5, 10, 6, 2, 187, 189, 5, 12, 7, 2, 188, 186, 3, 2, 2, 2, 188, 187, 3, 2, 2, 2, 189, 27, 3, 2, 2, 2, 190, 191, 7, 40, 2, 2, 191, 192, 5, 92, 47, 2, 192, 29, 3, 2, 2, 2, 193, 194, 7, 42, 2, 2, 194, 197, 5, 32, 17, 2, 195, 196, 7, 10, 2, 2, 196, 198, 5, 32, 17, 2, 197, 195, 3, 2, 2, 2, 197, 198, 3, 2, 2, 2, 198, 31, 3, 2, 2, 2, 199, 202, 7, 63, 2, 2, 200, 202, 5, 54, 28, 2, 201, 199, 3, 2, 2, 2, 201, 200, 3, 2, 2, 2, 202, 33, 3, 2, 2, 2, 203, 204, 7, 41, 2, 2, 204, 209, 5, 36, 19, 2, 205, 206, 7, 10, 2, 2, 206, 208, 5, 36, 19, 2, 207, 205, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, 209, 207, 3, 2, 2, 2, 209, 210, 3, 2, 2, 2, 210, 35, 3, 2, 2, 2, 211, 209, 3, 2, 2, 2, 212, 214, 5, 92, 47, 2, 213, 215, 7, 45, 2, 2, 214, 213, 3, 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 37, 3, 2, 2, 2, 216, 217, 7, 44, 2, 2, 217, 235, 5, 50, 26, 2, 218, 219, 7, 44, 2, 2, 219, 235, 5, 44, 23, 2, 220, 221, 7, 44, 2, 2, 221, 222, 5, 42, 22, 2, 222, 223, 5, 44, 23, 2, 223, 235, 3, 2, 2, 2, 224, 225, 7, 44, 2, 2, 225, 226, 5, 42, 22, 2, 226, 227, 5, 48, 25, 2, 227, 235, 3, 2, 2, 2, 228, 229, 7, 44, 2, 2, 229, 230, 5, 42, 22, 2, 230, 231, 5, 50, 26, 2, 231, 235, 3, 2, 2, 2, 232, 233, 7, 44, 2, 2, 233, 235, 5, 42, 22, 2, 234, 216, 3, 2, 2, 2, 234, 218, 3, 2, 2, 2, 234, 220, 3, 2, 2, 2, 234, 224, 3, 2, 2, 2, 234, 228, 3, 2, 2, 2, 234, 232, 3, 2, 2, 2, 235, 39, 3, 2, 2, 2, 236, 237, 7, 60, 2, 2, 237, 238, 7, 33, 2, 2, 238, 239, 5, 92, 47, 2, 239, 41, 3, 2, 2, 2, 240, 245, 5, 40, 21, 2, 241, 242, 7, 10, 2, 2, 242, 244, 5, 40, 21, 2, 243, 241, 3, 2, 2, 2, 244, 247, 3, 2, 2, 2, 245, 243, 3, 2, 2, 2, 245, 246, 3, 2, 2, 2, 246, 43, 3, 2, 2, 2, 247, 245, 3, 2, 2, 2, 248, 249, 7, 55, 2, 2, 249, 254, 5, 46, 24, 2, 250, 251, 7, 10, 2, 2, 251, 253, 5, 46, 24, 2, 252, 250, 3, 2, 2, 2, 253, 256, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 254, 255, 3, 2, 2, 2, 255, 45, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 257, 258, 7, 60, 2, 2, 258, 259, 7, 33, 2, 2, 259, 260, 5, 88, 45, 2, 260, 47, 3, 2, 2, 2, 261, 262, 7, 49, 2, 2, 262, 270, 5, 40, 21, 2, 263, 264, 7, 49, 2, 2, 264, 267, 7, 60, 2, 2, 265, 266, 7, 50, 2, 2, 266, 268, 7, 60, 2, 2, 267, 265, 3, 2, 2, 2, 267, 268, 3, 2, 2, 2, 268, 270, 3, 2, 2, 2, 269, 261, 3, 2, 2, 2, 269, 263, 3, 2, 2, 2, 270, 49, 3, 2, 2, 2, 271, 272, 7, 51, 2, 2, 272, 273, 7, 52, 2, 2, 273, 274, 7, 49, 2, 2, 274, 275, 7, 60, 2, 2, 275, 51, 3, 2, 2, 2, 276, 277, 7, 43, 2, 2, 277, 278, 7, 60, 2, 2, 278, 279, 7, 33, 2, 2, 279, 292, 5, 92, 47, 2, 280, 281, 7, 43, 2, 2, 281, 282, 7, 60, 2, 2, 282, 283, 7, 33, 2, 2, 283, 284, 7, 13, 2, 2, 284, 285, 5, 12, 7, 2, 285, 286, 7, 14, 2, 2, 286, 292, 3, 2, 2, 2, 287, 288, 7, 43, 2, 2, 288, 289, 7, 60, 2, 2, 289, 290, 7, 33, 2, 2, 290, 292, 5, 94, 48, 2, 291, 276, 3, 2, 2, 2, 291, 280, 3, 2, 2, 2, 291, 287, 3, 2, 2, 2, 292, 53, 3, 2, 2, 2, 293, 294, 7, 59, 2, 2, 294, 295, 7, 60, 2, 2, 295, 55, 3, 2, 2, 2, 296, 297, 7, 60, 2, 2, 297, 57, 3, 2, 2, 2, 298, 302, 5, 68, 35, 2, 299, 302, 5, 56, 29, 2, 300, 302, 5, 54, 28, 2, 301, 298, 3, 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 300, 3, 2, 2, 2, 302, 303, 3, 2, 2, 2, 303, 307, 7, 32, 2, 2, 304, 308, 5, 68, 35, 2, 305, 308, 5, 56, 29, 2, 306, 308, 5, 54, 28, 2, 307, 304, 3, 2, 2, 2, 307, 305, 3, 2, 2, 2, 307, 306, 3, 2, 2, 2, 308, 59, 3, 2, 2, 2, 309, 311, 7, 11, 2, 2, 310, 312, 5, 74, 38, 2, 311, 310, 3, 2, 2, 2, 311, 312, 3, 2, 2, 2, 312, 313, 3, 2, 2, 2, 313, 314, 7, 12, 2, 2, 314, 61, 3, 2, 2, 2, 315, 324, 7, 15, 2, 2, 316, 321, 5, 76, 39, 2, 317, 318, 7, 10, 2, 2, 318, 320, 5, 76, 39, 2, 319, 317, 3, 2, 2, 2, 320, 323, 3, 2, 2, 2, 321, 319, 3, 2, 2, 2, 321, 322, 3, 2, 2, 2, 322, 325, 3, 2, 2, 2, 323, 321, 3, 2, 2, 2, 324, 316, 3, 2, 2, 2, 324, 325, 3, 2, 2, 2, 325, 327, 3, 2, 2, 2, 326, 328, 7, 10, 2, 2, 327, 326, 3, 2, 2, 2, 327, 328, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 330, 7, 16, 2, 2, 330, 63, 3, 2, 2, 2, 331, 332, 7, 48, 2, 2, 332, 65, 3, 2, 2, 2, 333, 334, 9, 2, 2, 2, 334, 67, 3, 2, 2, 2, 335, 336, 7, 63, 2, 2, 336, 69, 3, 2, 2, 2, 337, 338, 7, 64, 2, 2, 338, 71, 3, 2, 2, 2, 339, 340, 9, 3, 2, 2, 340, 73, 3, 2, 2, 2, 341, 350, 5, 92, 47, 2, 342, 344, 7, 10, 2, 2, 343, 342, 3, 2, 2, 2, 344, 345, 3, 2, 2, 2, 345, 343, 3, 2, 2, 2, 345, 346, 3, 2, 2, 2, 346, 347, 3, 2, 2, 2, 347, 349, 5, 92, 47, 2, 348, 343, 3, 2, 2, 2, 349, 352, 3, 2, 2, 2, 350, 348, 3, 2, 2, 2, 350, 351, 3, 2, 2, 2, 351, 75, 3, 2, 2, 2, 352, 350, 3, 2, 2, 2, 353, 354, 5, 84, 43, 2, 354, 355, 7, 7, 2, 2, 355, 356, 5, 92, 47, 2, 356, 363, 3, 2, 2, 2, 357, 358, 5, 82, 42, 2, 358, 359, 7, 7, 2, 2, 359, 360, 5, 92, 47, 2, 360, 363, 3, 2, 2, 2, 361, 363, 5, 80, 41, 2, 362, 353, 3, 2, 2, 2, 362, 357, 3, 2, 2, 2, 362, 361, 3, 2, 2, 2, 363, 77, 3, 2, 2, 2, 364, 373, 7, 60, 2, 2, 365, 366, 7, 9, 2, 2, 366, 370, 5, 84, 43, 2, 367, 369, 5, 82, 42, 2, 368, 367, 3, 2, 2, 2, 369, 372, 3, 2, 2, 2, 370, 368, 3, 2, 2, 2, 370, 371, 3, 2, 2, 2, 371, 374, 3, 2, 2, 2, 372, 370, 3, 2, 2, 2, 373, 365, 3, 2, 2, 2, 374, 375, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 375, 376, 3, 2, 2, 2, 376, 406, 3, 2, 2, 2, 377, 378, 7, 60, 2, 2, 378, 389, 5, 82, 42, 2, 379, 380, 7, 9, 2, 2, 380, 384, 5, 84, 43, 2, 381, 383, 5, 82, 42, 2, 382, 381, 3, 2, 2, 2, 383, 386, 3, 2, 2, 2, 384, 382, 3, 2, 2, 2, 384, 385, 3, 2, 2, 2, 385, 388, 3, 2, 2, 2, 386, 384, 3, 2, 2, 2, 387, 379, 3, 2, 2, 2, 388, 391, 3, 2, 2, 2, 389, 387, 3, 2, 2, 2, 389, 390, 3, 2, 2, 2, 390, 402, 3, 2, 2, 2, 391, 389, 3, 2, 2, 2, 392, 397, 5, 82, 42, 2, 393, 394, 7, 9, 2, 2, 394, 396, 5, 84, 43, 2, 395, 393, 3, 2, 2, 2, 396, 399, 3, 2, 2, 2, 397, 395, 3, 2, 2, 2, 397, 398, 3, 2, 2, 2, 398, 401, 3, 2, 2, 2, 399, 397, 3, 2, 2, 2, 400, 392, 3, 2, 2, 2, 401, 404, 3, 2, 2, 2, 402, 400, 3, 2, 2, 2, 402, 403, 3, 2, 2, 2, 403, 406, 3, 2, 2, 2, 404, 402, 3, 2, 2, 2, 405, 364, 3, 2, 2, 2, 405, 377, 3, 2, 2, 2, 406, 79, 3, 2, 2, 2, 407, 408, 5, 56, 29, 2, 408, 81, 3, 2, 2, 2, 409, 410, 7, 11, 2, 2, 410, 411, 5, 92, 47, 2, 411, 412, 7, 12, 2, 2, 412, 83, 3, 2, 2, 2, 413, 416, 7, 60, 2, 2, 414, 416, 5, 66, 34, 2, 415, 413, 3, 2, 2, 2, 415, 414, 3, 2, 2, 2, 416, 85, 3, 2, 2, 2, 417, 422, 5, 92, 47, 2, 418, 419, 7, 10, 2, 2, 419, 421, 5, 92, 47, 2, 420, 418, 3, 2, 2, 2, 421, 424, 3, 2, 2, 2, 422, 420, 3, 2, 2, 2, 422, 423, 3, 2, 2, 2, 423, 87, 3, 2, 2, 2, 424, 422, 3, 2, 2, 2, 425, 426, 7, 60, 2, 2, 426, 427, 5, 90, 46, 2, 427, 89, 3, 2, 2, 2, 428, 437, 7, 13, 2, 2, 429, 434, 5, 92, 47, 2, 430, 431, 7, 10, 2, 2, 431, 433, 5, 92, 47, 2, 432, 430, 3, 2, 2, 2, 433, 436, 3, 2, 2, 2, 434, 432, 3, 2, 2, 2, 434, 435, 3, 2, 2, 2, 435, 438, 3, 2, 2, 2, 436, 434, 3, 2, 2, 2, 437, 429, 3, 2, 2, 2, 437, 438, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 440, 7, 14, 2, 2, 440, 91, 3, 2, 2, 2, 441, 442, 8, 47, 1, 2, 442, 443, 5, 106, 54, 2, 443, 444, 5, 92, 47, 22, 444, 462, 3, 2, 2, 2, 445, 462, 5, 88, 45, 2, 446, 447, 7, 13, 2, 2, 447, 448, 5, 86, 44, 2, 448, 449, 7, 14, 2, 2, 449, 462, 3, 2, 2, 2, 450, 462, 5, 58, 30, 2, 451, 462, 5, 66, 34, 2, 452, 462, 5, 68, 35, 2, 453, 462, 5, 70, 36, 2, 454, 462, 5, 64, 33, 2, 455, 462, 5, 60, 31, 2, 456, 462, 5, 62, 32, 2, 457, 462, 5, 56, 29, 2, 458, 462, 5, 78, 40, 2, 459, 462, 5, 72, 37, 2, 460, 462, 5, 54, 28, 2, 461, 441, 3, 2, 2, 2, 461, 445, 3, 2, 2, 2, 461, 446, 3, 2, 2, 2, 461, 450, 3, 2, 2, 2, 461, 451, 3, 2, 2, 2, 461, 452, 3, 2, 2, 2, 461, 453, 3, 2, 2, 2, 461, 454, 3, 2, 2, 2, 461, 455, 3, 2, 2, 2, 461, 456, 3, 2, 2, 2, 461, 457, 3, 2, 2, 2, 461, 458, 3, 2, 2, 2, 461, 459, 3, 2, 2, 2, 461, 460, 3, 2, 2, 2, 462, 496, 3, 2, 2, 2, 463, 464, 12, 21, 2, 2, 464, 465, 5, 100, 51, 2, 465, 466, 5, 92, 47, 22, 466, 495, 3, 2, 2, 2, 467, 468, 12, 20, 2, 2, 468, 469, 5, 102, 52, 2, 469, 470, 5, 92, 47, 21, 470, 495, 3, 2, 2, 2, 471, 472, 12, 19, 2, 2, 472, 473, 5, 104, 53, 2, 473, 474, 5, 92, 47, 20, 474, 495, 3, 2, 2, 2, 475, 476, 12, 16, 2, 2, 476, 479, 5, 96, 49, 2, 477, 480, 5, 98, 50, 2, 478, 480, 5, 100, 51, 2, 479, 477, 3, 2, 2, 2, 479, 478, 3, 2, 2, 2, 480, 481, 3, 2, 2, 2, 481, 482, 5, 92, 47, 17, 482, 495, 3, 2, 2, 2, 483, 484, 12, 15, 2, 2, 484, 485, 5, 98, 50, 2, 485, 486, 5, 92, 47, 16, 486, 495, 3, 2, 2, 2, 487, 488, 12, 14, 2, 2, 488, 490, 7, 34, 2, 2, 489, 491, 5, 92, 47, 2, 490, 489, 3, 2, 2, 2, 490, 491, 3, 2, 2, 2, 491, 492, 3, 2, 2, 2, 492, 493, 7, 7, 2, 2, 493, 495, 5, 92, 47, 15, 494, 463, 3, 2, 2, 2, 494, 467, 3, 2, 2, 2, 494, 471, 3, 2, 2, 2, 494, 475, 3, 2, 2, 2, 494, 483, 3, 2, 2, 2, 494, 487, 3, 2, 2, 2, 495, 498, 3, 2, 2, 2, 496, 494, 3, 2, 2, 2, 496, 497, 3, 2, 2, 2, 497, 93, 3, 2, 2, 2, 498, 496, 3, 2, 2, 2, 499, 500, 5, 92, 47, 2, 500, 502, 7, 34, 2, 2, 501, 503, 5, 92, 47, 2, 502, 501, 3, 2, 2, 2, 502, 503, 3, 2, 2, 2, 503, 504, 3, 2, 2, 2, 504, 505, 7, 7, 2, 2, 505, 506, 7, 13, 2, 2, 506, 507, 5, 12, 7, 2, 507, 508, 7, 14, 2, 2, 508, 528, 3, 2, 2, 2, 509, 510, 5, 92, 47, 2, 510, 511, 7, 34, 2, 2, 511, 512, 7, 13, 2, 2, 512, 513, 5, 12, 7, 2, 513, 514, 7, 14, 2, 2, 514, 515, 7, 7, 2, 2, 515, 516, 5, 92, 47, 2, 516, 528, 3, 2, 2, 2, 517, 518, 5, 92, 47, 2, 518, 519, 7, 34, 2, 2, 519, 520, 7, 13, 2, 2, 520, 521, 5, 12, 7, 2, 521, 522, 7, 14, 2, 2, 522, 523, 7, 7, 2, 2, 523, 524, 7, 13, 2, 2, 524, 525, 5, 12, 7, 2, 525, 526, 7, 14, 2, 2, 526, 528, 3, 2, 2, 2, 527, 499, 3, 2, 2, 2, 527, 509, 3, 2, 2, 2, 527, 517, 3, 2, 2, 2, 528, 95, 3, 2, 2, 2, 529, 530, 9, 4, 2, 2, 530, 97, 3, 2, 2, 2, 531, 535, 7, 58, 2, 2, 532, 533, 7, 57, 2, 2, 533, 535, 7, 58, 2, 2, 534, 531, 3, 2, 2, 2, 534, 532, 3, 2, 2, 2, 535, 99, 3, 2, 2, 2, 536, 537, 9, 5, 2, 2, 537, 101, 3, 2, 2, 2, 538, 539, 9, 6, 2, 2, 539, 103, 3, 2, 2, 2, 540, 541, 9, 7, 2, 2, 541, 105, 3, 2, 2, 2, 542, 543, 9, 8, 2, 2, 543, 107, 3, 2, 2, 2, 53, 113, 120, 124, 128, 133, 141, 147, 154, 170, 176, 180, 184, 188, 197, 201, 209, 214, 234, 245, 254, 267, 269, 291, 301, 307, 311, 321, 324, 327, 345, 350, 362, 370, 375, 384, 389, 397, 402, 405, 415, 422, 434, 437, 461, 479, 490, 494, 496, 502, 527, 534] \ No newline at end of file +[3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 64, 554, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, 18, 4, 19, 9, 19, 4, 20, 9, 20, 4, 21, 9, 21, 4, 22, 9, 22, 4, 23, 9, 23, 4, 24, 9, 24, 4, 25, 9, 25, 4, 26, 9, 26, 4, 27, 9, 27, 4, 28, 9, 28, 4, 29, 9, 29, 4, 30, 9, 30, 4, 31, 9, 31, 4, 32, 9, 32, 4, 33, 9, 33, 4, 34, 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, 9, 55, 4, 56, 9, 56, 3, 2, 3, 2, 3, 3, 7, 3, 116, 10, 3, 12, 3, 14, 3, 119, 11, 3, 3, 3, 3, 3, 3, 4, 3, 4, 5, 4, 125, 10, 4, 3, 5, 3, 5, 5, 5, 129, 10, 5, 3, 6, 3, 6, 5, 6, 133, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 138, 10, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 146, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 152, 10, 7, 3, 7, 3, 7, 3, 7, 7, 7, 157, 10, 7, 12, 7, 14, 7, 160, 11, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 175, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 181, 10, 11, 3, 12, 3, 12, 5, 12, 185, 10, 12, 3, 13, 3, 13, 5, 13, 189, 10, 13, 3, 14, 3, 14, 5, 14, 193, 10, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 5, 16, 202, 10, 16, 3, 17, 3, 17, 5, 17, 206, 10, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 212, 10, 18, 12, 18, 14, 18, 215, 11, 18, 3, 19, 3, 19, 5, 19, 219, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 239, 10, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, 3, 22, 7, 22, 248, 10, 22, 12, 22, 14, 22, 251, 11, 22, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 257, 10, 23, 12, 23, 14, 23, 260, 11, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 272, 10, 25, 5, 25, 274, 10, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 5, 27, 296, 10, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 5, 30, 306, 10, 30, 3, 30, 3, 30, 3, 30, 3, 30, 5, 30, 312, 10, 30, 3, 31, 3, 31, 5, 31, 316, 10, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 7, 32, 324, 10, 32, 12, 32, 14, 32, 327, 11, 32, 5, 32, 329, 10, 32, 3, 32, 5, 32, 332, 10, 32, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 6, 38, 348, 10, 38, 13, 38, 14, 38, 349, 3, 38, 7, 38, 353, 10, 38, 12, 38, 14, 38, 356, 11, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 5, 39, 367, 10, 39, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 373, 10, 40, 12, 40, 14, 40, 376, 11, 40, 6, 40, 378, 10, 40, 13, 40, 14, 40, 379, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 387, 10, 40, 12, 40, 14, 40, 390, 11, 40, 7, 40, 392, 10, 40, 12, 40, 14, 40, 395, 11, 40, 3, 40, 3, 40, 3, 40, 7, 40, 400, 10, 40, 12, 40, 14, 40, 403, 11, 40, 7, 40, 405, 10, 40, 12, 40, 14, 40, 408, 11, 40, 5, 40, 410, 10, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 5, 43, 420, 10, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 7, 46, 433, 10, 46, 12, 46, 14, 46, 436, 11, 46, 5, 46, 438, 10, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 459, 10, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 473, 10, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 496, 10, 47, 3, 47, 3, 47, 7, 47, 500, 10, 47, 12, 47, 14, 47, 503, 11, 47, 3, 48, 3, 48, 3, 48, 5, 48, 508, 10, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 533, 10, 48, 3, 49, 3, 49, 3, 50, 3, 50, 3, 50, 5, 50, 540, 10, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 2, 3, 92, 57, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 2, 9, 3, 2, 61, 62, 3, 2, 46, 47, 4, 2, 46, 46, 53, 54, 3, 2, 17, 22, 3, 2, 23, 25, 3, 2, 26, 27, 4, 2, 26, 27, 56, 57, 2, 583, 2, 112, 3, 2, 2, 2, 4, 117, 3, 2, 2, 2, 6, 124, 3, 2, 2, 2, 8, 128, 3, 2, 2, 2, 10, 145, 3, 2, 2, 2, 12, 147, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, 16, 165, 3, 2, 2, 2, 18, 174, 3, 2, 2, 2, 20, 180, 3, 2, 2, 2, 22, 184, 3, 2, 2, 2, 24, 188, 3, 2, 2, 2, 26, 192, 3, 2, 2, 2, 28, 194, 3, 2, 2, 2, 30, 197, 3, 2, 2, 2, 32, 205, 3, 2, 2, 2, 34, 207, 3, 2, 2, 2, 36, 216, 3, 2, 2, 2, 38, 238, 3, 2, 2, 2, 40, 240, 3, 2, 2, 2, 42, 244, 3, 2, 2, 2, 44, 252, 3, 2, 2, 2, 46, 261, 3, 2, 2, 2, 48, 273, 3, 2, 2, 2, 50, 275, 3, 2, 2, 2, 52, 295, 3, 2, 2, 2, 54, 297, 3, 2, 2, 2, 56, 300, 3, 2, 2, 2, 58, 305, 3, 2, 2, 2, 60, 313, 3, 2, 2, 2, 62, 319, 3, 2, 2, 2, 64, 335, 3, 2, 2, 2, 66, 337, 3, 2, 2, 2, 68, 339, 3, 2, 2, 2, 70, 341, 3, 2, 2, 2, 72, 343, 3, 2, 2, 2, 74, 345, 3, 2, 2, 2, 76, 366, 3, 2, 2, 2, 78, 409, 3, 2, 2, 2, 80, 411, 3, 2, 2, 2, 82, 413, 3, 2, 2, 2, 84, 419, 3, 2, 2, 2, 86, 421, 3, 2, 2, 2, 88, 425, 3, 2, 2, 2, 90, 428, 3, 2, 2, 2, 92, 458, 3, 2, 2, 2, 94, 532, 3, 2, 2, 2, 96, 534, 3, 2, 2, 2, 98, 539, 3, 2, 2, 2, 100, 541, 3, 2, 2, 2, 102, 543, 3, 2, 2, 2, 104, 545, 3, 2, 2, 2, 106, 547, 3, 2, 2, 2, 108, 549, 3, 2, 2, 2, 110, 551, 3, 2, 2, 2, 112, 113, 5, 4, 3, 2, 113, 3, 3, 2, 2, 2, 114, 116, 5, 6, 4, 2, 115, 114, 3, 2, 2, 2, 116, 119, 3, 2, 2, 2, 117, 115, 3, 2, 2, 2, 117, 118, 3, 2, 2, 2, 118, 120, 3, 2, 2, 2, 119, 117, 3, 2, 2, 2, 120, 121, 5, 8, 5, 2, 121, 5, 3, 2, 2, 2, 122, 125, 5, 88, 45, 2, 123, 125, 5, 52, 27, 2, 124, 122, 3, 2, 2, 2, 124, 123, 3, 2, 2, 2, 125, 7, 3, 2, 2, 2, 126, 129, 5, 10, 6, 2, 127, 129, 5, 12, 7, 2, 128, 126, 3, 2, 2, 2, 128, 127, 3, 2, 2, 2, 129, 9, 3, 2, 2, 2, 130, 132, 7, 38, 2, 2, 131, 133, 7, 39, 2, 2, 132, 131, 3, 2, 2, 2, 132, 133, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 146, 5, 92, 47, 2, 135, 137, 7, 38, 2, 2, 136, 138, 7, 39, 2, 2, 137, 136, 3, 2, 2, 2, 137, 138, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 140, 7, 13, 2, 2, 140, 141, 5, 12, 7, 2, 141, 142, 7, 14, 2, 2, 142, 146, 3, 2, 2, 2, 143, 144, 7, 38, 2, 2, 144, 146, 5, 94, 48, 2, 145, 130, 3, 2, 2, 2, 145, 135, 3, 2, 2, 2, 145, 143, 3, 2, 2, 2, 146, 11, 3, 2, 2, 2, 147, 148, 7, 37, 2, 2, 148, 151, 5, 14, 8, 2, 149, 150, 7, 10, 2, 2, 150, 152, 5, 16, 9, 2, 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, 154, 7, 58, 2, 2, 154, 158, 5, 18, 10, 2, 155, 157, 5, 24, 13, 2, 156, 155, 3, 2, 2, 2, 157, 160, 3, 2, 2, 2, 158, 156, 3, 2, 2, 2, 158, 159, 3, 2, 2, 2, 159, 161, 3, 2, 2, 2, 160, 158, 3, 2, 2, 2, 161, 162, 5, 26, 14, 2, 162, 13, 3, 2, 2, 2, 163, 164, 7, 60, 2, 2, 164, 15, 3, 2, 2, 2, 165, 166, 7, 60, 2, 2, 166, 17, 3, 2, 2, 2, 167, 175, 5, 88, 45, 2, 168, 175, 5, 60, 31, 2, 169, 175, 5, 62, 32, 2, 170, 175, 5, 56, 29, 2, 171, 175, 5, 78, 40, 2, 172, 175, 5, 58, 30, 2, 173, 175, 5, 54, 28, 2, 174, 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 174, 172, 3, 2, 2, 2, 174, 173, 3, 2, 2, 2, 175, 19, 3, 2, 2, 2, 176, 181, 5, 30, 16, 2, 177, 181, 5, 34, 18, 2, 178, 181, 5, 28, 15, 2, 179, 181, 5, 38, 20, 2, 180, 176, 3, 2, 2, 2, 180, 177, 3, 2, 2, 2, 180, 178, 3, 2, 2, 2, 180, 179, 3, 2, 2, 2, 181, 21, 3, 2, 2, 2, 182, 185, 5, 52, 27, 2, 183, 185, 5, 88, 45, 2, 184, 182, 3, 2, 2, 2, 184, 183, 3, 2, 2, 2, 185, 23, 3, 2, 2, 2, 186, 189, 5, 22, 12, 2, 187, 189, 5, 20, 11, 2, 188, 186, 3, 2, 2, 2, 188, 187, 3, 2, 2, 2, 189, 25, 3, 2, 2, 2, 190, 193, 5, 10, 6, 2, 191, 193, 5, 12, 7, 2, 192, 190, 3, 2, 2, 2, 192, 191, 3, 2, 2, 2, 193, 27, 3, 2, 2, 2, 194, 195, 7, 40, 2, 2, 195, 196, 5, 92, 47, 2, 196, 29, 3, 2, 2, 2, 197, 198, 7, 42, 2, 2, 198, 201, 5, 32, 17, 2, 199, 200, 7, 10, 2, 2, 200, 202, 5, 32, 17, 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 31, 3, 2, 2, 2, 203, 206, 7, 63, 2, 2, 204, 206, 5, 54, 28, 2, 205, 203, 3, 2, 2, 2, 205, 204, 3, 2, 2, 2, 206, 33, 3, 2, 2, 2, 207, 208, 7, 41, 2, 2, 208, 213, 5, 36, 19, 2, 209, 210, 7, 10, 2, 2, 210, 212, 5, 36, 19, 2, 211, 209, 3, 2, 2, 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 213, 214, 3, 2, 2, 2, 214, 35, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 216, 218, 5, 92, 47, 2, 217, 219, 7, 45, 2, 2, 218, 217, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 219, 37, 3, 2, 2, 2, 220, 221, 7, 44, 2, 2, 221, 239, 5, 50, 26, 2, 222, 223, 7, 44, 2, 2, 223, 239, 5, 44, 23, 2, 224, 225, 7, 44, 2, 2, 225, 226, 5, 42, 22, 2, 226, 227, 5, 44, 23, 2, 227, 239, 3, 2, 2, 2, 228, 229, 7, 44, 2, 2, 229, 230, 5, 42, 22, 2, 230, 231, 5, 48, 25, 2, 231, 239, 3, 2, 2, 2, 232, 233, 7, 44, 2, 2, 233, 234, 5, 42, 22, 2, 234, 235, 5, 50, 26, 2, 235, 239, 3, 2, 2, 2, 236, 237, 7, 44, 2, 2, 237, 239, 5, 42, 22, 2, 238, 220, 3, 2, 2, 2, 238, 222, 3, 2, 2, 2, 238, 224, 3, 2, 2, 2, 238, 228, 3, 2, 2, 2, 238, 232, 3, 2, 2, 2, 238, 236, 3, 2, 2, 2, 239, 39, 3, 2, 2, 2, 240, 241, 7, 60, 2, 2, 241, 242, 7, 33, 2, 2, 242, 243, 5, 92, 47, 2, 243, 41, 3, 2, 2, 2, 244, 249, 5, 40, 21, 2, 245, 246, 7, 10, 2, 2, 246, 248, 5, 40, 21, 2, 247, 245, 3, 2, 2, 2, 248, 251, 3, 2, 2, 2, 249, 247, 3, 2, 2, 2, 249, 250, 3, 2, 2, 2, 250, 43, 3, 2, 2, 2, 251, 249, 3, 2, 2, 2, 252, 253, 7, 55, 2, 2, 253, 258, 5, 46, 24, 2, 254, 255, 7, 10, 2, 2, 255, 257, 5, 46, 24, 2, 256, 254, 3, 2, 2, 2, 257, 260, 3, 2, 2, 2, 258, 256, 3, 2, 2, 2, 258, 259, 3, 2, 2, 2, 259, 45, 3, 2, 2, 2, 260, 258, 3, 2, 2, 2, 261, 262, 7, 60, 2, 2, 262, 263, 7, 33, 2, 2, 263, 264, 5, 88, 45, 2, 264, 47, 3, 2, 2, 2, 265, 266, 7, 49, 2, 2, 266, 274, 5, 40, 21, 2, 267, 268, 7, 49, 2, 2, 268, 271, 7, 60, 2, 2, 269, 270, 7, 50, 2, 2, 270, 272, 7, 60, 2, 2, 271, 269, 3, 2, 2, 2, 271, 272, 3, 2, 2, 2, 272, 274, 3, 2, 2, 2, 273, 265, 3, 2, 2, 2, 273, 267, 3, 2, 2, 2, 274, 49, 3, 2, 2, 2, 275, 276, 7, 51, 2, 2, 276, 277, 7, 52, 2, 2, 277, 278, 7, 49, 2, 2, 278, 279, 7, 60, 2, 2, 279, 51, 3, 2, 2, 2, 280, 281, 7, 43, 2, 2, 281, 282, 7, 60, 2, 2, 282, 283, 7, 33, 2, 2, 283, 296, 5, 92, 47, 2, 284, 285, 7, 43, 2, 2, 285, 286, 7, 60, 2, 2, 286, 287, 7, 33, 2, 2, 287, 288, 7, 13, 2, 2, 288, 289, 5, 12, 7, 2, 289, 290, 7, 14, 2, 2, 290, 296, 3, 2, 2, 2, 291, 292, 7, 43, 2, 2, 292, 293, 7, 60, 2, 2, 293, 294, 7, 33, 2, 2, 294, 296, 5, 94, 48, 2, 295, 280, 3, 2, 2, 2, 295, 284, 3, 2, 2, 2, 295, 291, 3, 2, 2, 2, 296, 53, 3, 2, 2, 2, 297, 298, 7, 59, 2, 2, 298, 299, 7, 60, 2, 2, 299, 55, 3, 2, 2, 2, 300, 301, 7, 60, 2, 2, 301, 57, 3, 2, 2, 2, 302, 306, 5, 68, 35, 2, 303, 306, 5, 56, 29, 2, 304, 306, 5, 54, 28, 2, 305, 302, 3, 2, 2, 2, 305, 303, 3, 2, 2, 2, 305, 304, 3, 2, 2, 2, 306, 307, 3, 2, 2, 2, 307, 311, 7, 32, 2, 2, 308, 312, 5, 68, 35, 2, 309, 312, 5, 56, 29, 2, 310, 312, 5, 54, 28, 2, 311, 308, 3, 2, 2, 2, 311, 309, 3, 2, 2, 2, 311, 310, 3, 2, 2, 2, 312, 59, 3, 2, 2, 2, 313, 315, 7, 11, 2, 2, 314, 316, 5, 74, 38, 2, 315, 314, 3, 2, 2, 2, 315, 316, 3, 2, 2, 2, 316, 317, 3, 2, 2, 2, 317, 318, 7, 12, 2, 2, 318, 61, 3, 2, 2, 2, 319, 328, 7, 15, 2, 2, 320, 325, 5, 76, 39, 2, 321, 322, 7, 10, 2, 2, 322, 324, 5, 76, 39, 2, 323, 321, 3, 2, 2, 2, 324, 327, 3, 2, 2, 2, 325, 323, 3, 2, 2, 2, 325, 326, 3, 2, 2, 2, 326, 329, 3, 2, 2, 2, 327, 325, 3, 2, 2, 2, 328, 320, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 331, 3, 2, 2, 2, 330, 332, 7, 10, 2, 2, 331, 330, 3, 2, 2, 2, 331, 332, 3, 2, 2, 2, 332, 333, 3, 2, 2, 2, 333, 334, 7, 16, 2, 2, 334, 63, 3, 2, 2, 2, 335, 336, 7, 48, 2, 2, 336, 65, 3, 2, 2, 2, 337, 338, 9, 2, 2, 2, 338, 67, 3, 2, 2, 2, 339, 340, 7, 63, 2, 2, 340, 69, 3, 2, 2, 2, 341, 342, 7, 64, 2, 2, 342, 71, 3, 2, 2, 2, 343, 344, 9, 3, 2, 2, 344, 73, 3, 2, 2, 2, 345, 354, 5, 92, 47, 2, 346, 348, 7, 10, 2, 2, 347, 346, 3, 2, 2, 2, 348, 349, 3, 2, 2, 2, 349, 347, 3, 2, 2, 2, 349, 350, 3, 2, 2, 2, 350, 351, 3, 2, 2, 2, 351, 353, 5, 92, 47, 2, 352, 347, 3, 2, 2, 2, 353, 356, 3, 2, 2, 2, 354, 352, 3, 2, 2, 2, 354, 355, 3, 2, 2, 2, 355, 75, 3, 2, 2, 2, 356, 354, 3, 2, 2, 2, 357, 358, 5, 84, 43, 2, 358, 359, 7, 7, 2, 2, 359, 360, 5, 92, 47, 2, 360, 367, 3, 2, 2, 2, 361, 362, 5, 82, 42, 2, 362, 363, 7, 7, 2, 2, 363, 364, 5, 92, 47, 2, 364, 367, 3, 2, 2, 2, 365, 367, 5, 80, 41, 2, 366, 357, 3, 2, 2, 2, 366, 361, 3, 2, 2, 2, 366, 365, 3, 2, 2, 2, 367, 77, 3, 2, 2, 2, 368, 377, 7, 60, 2, 2, 369, 370, 7, 9, 2, 2, 370, 374, 5, 84, 43, 2, 371, 373, 5, 82, 42, 2, 372, 371, 3, 2, 2, 2, 373, 376, 3, 2, 2, 2, 374, 372, 3, 2, 2, 2, 374, 375, 3, 2, 2, 2, 375, 378, 3, 2, 2, 2, 376, 374, 3, 2, 2, 2, 377, 369, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, 379, 377, 3, 2, 2, 2, 379, 380, 3, 2, 2, 2, 380, 410, 3, 2, 2, 2, 381, 382, 7, 60, 2, 2, 382, 393, 5, 82, 42, 2, 383, 384, 7, 9, 2, 2, 384, 388, 5, 84, 43, 2, 385, 387, 5, 82, 42, 2, 386, 385, 3, 2, 2, 2, 387, 390, 3, 2, 2, 2, 388, 386, 3, 2, 2, 2, 388, 389, 3, 2, 2, 2, 389, 392, 3, 2, 2, 2, 390, 388, 3, 2, 2, 2, 391, 383, 3, 2, 2, 2, 392, 395, 3, 2, 2, 2, 393, 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 406, 3, 2, 2, 2, 395, 393, 3, 2, 2, 2, 396, 401, 5, 82, 42, 2, 397, 398, 7, 9, 2, 2, 398, 400, 5, 84, 43, 2, 399, 397, 3, 2, 2, 2, 400, 403, 3, 2, 2, 2, 401, 399, 3, 2, 2, 2, 401, 402, 3, 2, 2, 2, 402, 405, 3, 2, 2, 2, 403, 401, 3, 2, 2, 2, 404, 396, 3, 2, 2, 2, 405, 408, 3, 2, 2, 2, 406, 404, 3, 2, 2, 2, 406, 407, 3, 2, 2, 2, 407, 410, 3, 2, 2, 2, 408, 406, 3, 2, 2, 2, 409, 368, 3, 2, 2, 2, 409, 381, 3, 2, 2, 2, 410, 79, 3, 2, 2, 2, 411, 412, 5, 56, 29, 2, 412, 81, 3, 2, 2, 2, 413, 414, 7, 11, 2, 2, 414, 415, 5, 92, 47, 2, 415, 416, 7, 12, 2, 2, 416, 83, 3, 2, 2, 2, 417, 420, 7, 60, 2, 2, 418, 420, 5, 66, 34, 2, 419, 417, 3, 2, 2, 2, 419, 418, 3, 2, 2, 2, 420, 85, 3, 2, 2, 2, 421, 422, 7, 13, 2, 2, 422, 423, 5, 92, 47, 2, 423, 424, 7, 14, 2, 2, 424, 87, 3, 2, 2, 2, 425, 426, 7, 60, 2, 2, 426, 427, 5, 90, 46, 2, 427, 89, 3, 2, 2, 2, 428, 437, 7, 13, 2, 2, 429, 434, 5, 92, 47, 2, 430, 431, 7, 10, 2, 2, 431, 433, 5, 92, 47, 2, 432, 430, 3, 2, 2, 2, 433, 436, 3, 2, 2, 2, 434, 432, 3, 2, 2, 2, 434, 435, 3, 2, 2, 2, 435, 438, 3, 2, 2, 2, 436, 434, 3, 2, 2, 2, 437, 429, 3, 2, 2, 2, 437, 438, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 440, 7, 14, 2, 2, 440, 91, 3, 2, 2, 2, 441, 442, 8, 47, 1, 2, 442, 443, 5, 110, 56, 2, 443, 444, 5, 92, 47, 24, 444, 459, 3, 2, 2, 2, 445, 459, 5, 88, 45, 2, 446, 459, 5, 86, 44, 2, 447, 459, 5, 58, 30, 2, 448, 459, 5, 66, 34, 2, 449, 459, 5, 68, 35, 2, 450, 459, 5, 70, 36, 2, 451, 459, 5, 64, 33, 2, 452, 459, 5, 60, 31, 2, 453, 459, 5, 62, 32, 2, 454, 459, 5, 56, 29, 2, 455, 459, 5, 78, 40, 2, 456, 459, 5, 72, 37, 2, 457, 459, 5, 54, 28, 2, 458, 441, 3, 2, 2, 2, 458, 445, 3, 2, 2, 2, 458, 446, 3, 2, 2, 2, 458, 447, 3, 2, 2, 2, 458, 448, 3, 2, 2, 2, 458, 449, 3, 2, 2, 2, 458, 450, 3, 2, 2, 2, 458, 451, 3, 2, 2, 2, 458, 452, 3, 2, 2, 2, 458, 453, 3, 2, 2, 2, 458, 454, 3, 2, 2, 2, 458, 455, 3, 2, 2, 2, 458, 456, 3, 2, 2, 2, 458, 457, 3, 2, 2, 2, 459, 501, 3, 2, 2, 2, 460, 461, 12, 23, 2, 2, 461, 462, 5, 106, 54, 2, 462, 463, 5, 92, 47, 24, 463, 500, 3, 2, 2, 2, 464, 465, 12, 22, 2, 2, 465, 466, 5, 108, 55, 2, 466, 467, 5, 92, 47, 23, 467, 500, 3, 2, 2, 2, 468, 469, 12, 19, 2, 2, 469, 472, 5, 96, 49, 2, 470, 473, 5, 98, 50, 2, 471, 473, 5, 100, 51, 2, 472, 470, 3, 2, 2, 2, 472, 471, 3, 2, 2, 2, 473, 474, 3, 2, 2, 2, 474, 475, 5, 92, 47, 20, 475, 500, 3, 2, 2, 2, 476, 477, 12, 18, 2, 2, 477, 478, 5, 98, 50, 2, 478, 479, 5, 92, 47, 19, 479, 500, 3, 2, 2, 2, 480, 481, 12, 17, 2, 2, 481, 482, 5, 100, 51, 2, 482, 483, 5, 92, 47, 18, 483, 500, 3, 2, 2, 2, 484, 485, 12, 16, 2, 2, 485, 486, 5, 102, 52, 2, 486, 487, 5, 92, 47, 17, 487, 500, 3, 2, 2, 2, 488, 489, 12, 15, 2, 2, 489, 490, 5, 104, 53, 2, 490, 491, 5, 92, 47, 16, 491, 500, 3, 2, 2, 2, 492, 493, 12, 14, 2, 2, 493, 495, 7, 34, 2, 2, 494, 496, 5, 92, 47, 2, 495, 494, 3, 2, 2, 2, 495, 496, 3, 2, 2, 2, 496, 497, 3, 2, 2, 2, 497, 498, 7, 7, 2, 2, 498, 500, 5, 92, 47, 15, 499, 460, 3, 2, 2, 2, 499, 464, 3, 2, 2, 2, 499, 468, 3, 2, 2, 2, 499, 476, 3, 2, 2, 2, 499, 480, 3, 2, 2, 2, 499, 484, 3, 2, 2, 2, 499, 488, 3, 2, 2, 2, 499, 492, 3, 2, 2, 2, 500, 503, 3, 2, 2, 2, 501, 499, 3, 2, 2, 2, 501, 502, 3, 2, 2, 2, 502, 93, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 504, 505, 5, 92, 47, 2, 505, 507, 7, 34, 2, 2, 506, 508, 5, 92, 47, 2, 507, 506, 3, 2, 2, 2, 507, 508, 3, 2, 2, 2, 508, 509, 3, 2, 2, 2, 509, 510, 7, 7, 2, 2, 510, 511, 7, 13, 2, 2, 511, 512, 5, 12, 7, 2, 512, 513, 7, 14, 2, 2, 513, 533, 3, 2, 2, 2, 514, 515, 5, 92, 47, 2, 515, 516, 7, 34, 2, 2, 516, 517, 7, 13, 2, 2, 517, 518, 5, 12, 7, 2, 518, 519, 7, 14, 2, 2, 519, 520, 7, 7, 2, 2, 520, 521, 5, 92, 47, 2, 521, 533, 3, 2, 2, 2, 522, 523, 5, 92, 47, 2, 523, 524, 7, 34, 2, 2, 524, 525, 7, 13, 2, 2, 525, 526, 5, 12, 7, 2, 526, 527, 7, 14, 2, 2, 527, 528, 7, 7, 2, 2, 528, 529, 7, 13, 2, 2, 529, 530, 5, 12, 7, 2, 530, 531, 7, 14, 2, 2, 531, 533, 3, 2, 2, 2, 532, 504, 3, 2, 2, 2, 532, 514, 3, 2, 2, 2, 532, 522, 3, 2, 2, 2, 533, 95, 3, 2, 2, 2, 534, 535, 9, 4, 2, 2, 535, 97, 3, 2, 2, 2, 536, 540, 7, 58, 2, 2, 537, 538, 7, 57, 2, 2, 538, 540, 7, 58, 2, 2, 539, 536, 3, 2, 2, 2, 539, 537, 3, 2, 2, 2, 540, 99, 3, 2, 2, 2, 541, 542, 9, 5, 2, 2, 542, 101, 3, 2, 2, 2, 543, 544, 7, 30, 2, 2, 544, 103, 3, 2, 2, 2, 545, 546, 7, 31, 2, 2, 546, 105, 3, 2, 2, 2, 547, 548, 9, 6, 2, 2, 548, 107, 3, 2, 2, 2, 549, 550, 9, 7, 2, 2, 550, 109, 3, 2, 2, 2, 551, 552, 9, 8, 2, 2, 552, 111, 3, 2, 2, 2, 52, 117, 124, 128, 132, 137, 145, 151, 158, 174, 180, 184, 188, 192, 201, 205, 213, 218, 238, 249, 258, 271, 273, 295, 305, 311, 315, 325, 328, 331, 349, 354, 366, 374, 379, 388, 393, 401, 406, 409, 419, 434, 437, 458, 472, 495, 499, 501, 507, 532, 539] \ No newline at end of file diff --git a/pkg/parser/fql/FqlParser.tokens b/pkg/parser/fql/FqlParser.tokens index bc38f772..15deb142 100644 --- a/pkg/parser/fql/FqlParser.tokens +++ b/pkg/parser/fql/FqlParser.tokens @@ -18,13 +18,13 @@ Eq=17 Gte=18 Lte=19 Neq=20 -Plus=21 -Minus=22 -MinusMinus=23 -PlusPlus=24 -Multi=25 -Div=26 -Mod=27 +Multi=21 +Div=22 +Mod=23 +Plus=24 +Minus=25 +MinusMinus=26 +PlusPlus=27 And=28 Or=29 Range=30 @@ -76,13 +76,13 @@ FloatLiteral=62 '>='=18 '<='=19 '!='=20 -'+'=21 -'-'=22 -'--'=23 -'++'=24 -'*'=25 -'/'=26 -'%'=27 +'*'=21 +'/'=22 +'%'=23 +'+'=24 +'-'=25 +'--'=26 +'++'=27 '='=31 '?'=32 '!~'=33 diff --git a/pkg/parser/fql/fql_lexer.go b/pkg/parser/fql/fql_lexer.go index 091e3bff..11d413f2 100644 --- a/pkg/parser/fql/fql_lexer.go +++ b/pkg/parser/fql/fql_lexer.go @@ -35,8 +35,8 @@ var serializedLexerAtn = []uint16{ 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 11, 3, 11, 3, 12, 3, 12, 3, 13, 3, 13, 3, 14, 3, 14, 3, 15, 3, 15, 3, 16, 3, 16, 3, 17, 3, 17, 3, 18, 3, 18, 3, 18, 3, 19, 3, 19, 3, 19, 3, 20, 3, 20, 3, 20, 3, 21, 3, - 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, - 3, 25, 3, 26, 3, 26, 3, 27, 3, 27, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, + 21, 3, 21, 3, 22, 3, 22, 3, 23, 3, 23, 3, 24, 3, 24, 3, 25, 3, 25, 3, 26, + 3, 26, 3, 27, 3, 27, 3, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, 3, 29, 3, 29, 3, 29, 5, 29, 237, 10, 29, 3, 30, 3, 30, 3, 30, 3, 30, 5, 30, 243, 10, 30, 3, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 34, 3, 35, 3, 35, 3, 35, 3, 36, 3, 36, 3, 36, 3, 36, 3, 37, 3, 37, 3, @@ -102,8 +102,8 @@ var serializedLexerAtn = []uint16{ 3, 2, 2, 2, 27, 195, 3, 2, 2, 2, 29, 197, 3, 2, 2, 2, 31, 199, 3, 2, 2, 2, 33, 201, 3, 2, 2, 2, 35, 203, 3, 2, 2, 2, 37, 206, 3, 2, 2, 2, 39, 209, 3, 2, 2, 2, 41, 212, 3, 2, 2, 2, 43, 215, 3, 2, 2, 2, 45, 217, 3, 2, 2, - 2, 47, 219, 3, 2, 2, 2, 49, 222, 3, 2, 2, 2, 51, 225, 3, 2, 2, 2, 53, 227, - 3, 2, 2, 2, 55, 229, 3, 2, 2, 2, 57, 236, 3, 2, 2, 2, 59, 242, 3, 2, 2, + 2, 47, 219, 3, 2, 2, 2, 49, 221, 3, 2, 2, 2, 51, 223, 3, 2, 2, 2, 53, 225, + 3, 2, 2, 2, 55, 228, 3, 2, 2, 2, 57, 236, 3, 2, 2, 2, 59, 242, 3, 2, 2, 2, 61, 244, 3, 2, 2, 2, 63, 247, 3, 2, 2, 2, 65, 249, 3, 2, 2, 2, 67, 251, 3, 2, 2, 2, 69, 254, 3, 2, 2, 2, 71, 257, 3, 2, 2, 2, 73, 261, 3, 2, 2, 2, 75, 268, 3, 2, 2, 2, 77, 277, 3, 2, 2, 2, 79, 284, 3, 2, 2, 2, 81, 289, @@ -139,11 +139,11 @@ var serializedLexerAtn = []uint16{ 36, 3, 2, 2, 2, 206, 207, 7, 64, 2, 2, 207, 208, 7, 63, 2, 2, 208, 38, 3, 2, 2, 2, 209, 210, 7, 62, 2, 2, 210, 211, 7, 63, 2, 2, 211, 40, 3, 2, 2, 2, 212, 213, 7, 35, 2, 2, 213, 214, 7, 63, 2, 2, 214, 42, 3, 2, 2, 2, - 215, 216, 7, 45, 2, 2, 216, 44, 3, 2, 2, 2, 217, 218, 7, 47, 2, 2, 218, - 46, 3, 2, 2, 2, 219, 220, 7, 47, 2, 2, 220, 221, 7, 47, 2, 2, 221, 48, - 3, 2, 2, 2, 222, 223, 7, 45, 2, 2, 223, 224, 7, 45, 2, 2, 224, 50, 3, 2, - 2, 2, 225, 226, 7, 44, 2, 2, 226, 52, 3, 2, 2, 2, 227, 228, 7, 49, 2, 2, - 228, 54, 3, 2, 2, 2, 229, 230, 7, 39, 2, 2, 230, 56, 3, 2, 2, 2, 231, 232, + 215, 216, 7, 44, 2, 2, 216, 44, 3, 2, 2, 2, 217, 218, 7, 49, 2, 2, 218, + 46, 3, 2, 2, 2, 219, 220, 7, 39, 2, 2, 220, 48, 3, 2, 2, 2, 221, 222, 7, + 45, 2, 2, 222, 50, 3, 2, 2, 2, 223, 224, 7, 47, 2, 2, 224, 52, 3, 2, 2, + 2, 225, 226, 7, 47, 2, 2, 226, 227, 7, 47, 2, 2, 227, 54, 3, 2, 2, 2, 228, + 229, 7, 45, 2, 2, 229, 230, 7, 45, 2, 2, 230, 56, 3, 2, 2, 2, 231, 232, 7, 67, 2, 2, 232, 233, 7, 80, 2, 2, 233, 237, 7, 70, 2, 2, 234, 235, 7, 40, 2, 2, 235, 237, 7, 40, 2, 2, 236, 231, 3, 2, 2, 2, 236, 234, 3, 2, 2, 2, 237, 58, 3, 2, 2, 2, 238, 239, 7, 81, 2, 2, 239, 243, 7, 84, 2, 2, @@ -261,8 +261,8 @@ var lexerModeNames = []string{ var lexerLiteralNames = []string{ "", "", "", "", "", "':'", "';'", "'.'", "','", "'['", "']'", "'('", "')'", - "'{'", "'}'", "'>'", "'<'", "'=='", "'>='", "'<='", "'!='", "'+'", "'-'", - "'--'", "'++'", "'*'", "'/'", "'%'", "", "", "", "'='", "'?'", "'!~'", + "'{'", "'}'", "'>'", "'<'", "'=='", "'>='", "'<='", "'!='", "'*'", "'/'", + "'%'", "'+'", "'-'", "'--'", "'++'", "", "", "", "'='", "'?'", "'!~'", "'=~'", "'FOR'", "'RETURN'", "'DISTINCT'", "'FILTER'", "'SORT'", "'LIMIT'", "'LET'", "'COLLECT'", "", "'NONE'", "'NULL'", "", "'INTO'", "'KEEP'", "'WITH'", "'COUNT'", "'ALL'", "'ANY'", "'AGGREGATE'", "'LIKE'", "", "'IN'", "'@'", @@ -272,7 +272,7 @@ var lexerSymbolicNames = []string{ "", "MultiLineComment", "SingleLineComment", "WhiteSpaces", "LineTerminator", "Colon", "SemiColon", "Dot", "Comma", "OpenBracket", "CloseBracket", "OpenParen", "CloseParen", "OpenBrace", "CloseBrace", "Gt", "Lt", "Eq", "Gte", "Lte", - "Neq", "Plus", "Minus", "MinusMinus", "PlusPlus", "Multi", "Div", "Mod", + "Neq", "Multi", "Div", "Mod", "Plus", "Minus", "MinusMinus", "PlusPlus", "And", "Or", "Range", "Assign", "QuestionMark", "RegexNotMatch", "RegexMatch", "For", "Return", "Distinct", "Filter", "Sort", "Limit", "Let", "Collect", "SortDirection", "None", "Null", "BooleanLiteral", "Into", "Keep", "With", @@ -284,7 +284,7 @@ var lexerRuleNames = []string{ "MultiLineComment", "SingleLineComment", "WhiteSpaces", "LineTerminator", "Colon", "SemiColon", "Dot", "Comma", "OpenBracket", "CloseBracket", "OpenParen", "CloseParen", "OpenBrace", "CloseBrace", "Gt", "Lt", "Eq", "Gte", "Lte", - "Neq", "Plus", "Minus", "MinusMinus", "PlusPlus", "Multi", "Div", "Mod", + "Neq", "Multi", "Div", "Mod", "Plus", "Minus", "MinusMinus", "PlusPlus", "And", "Or", "Range", "Assign", "QuestionMark", "RegexNotMatch", "RegexMatch", "For", "Return", "Distinct", "Filter", "Sort", "Limit", "Let", "Collect", "SortDirection", "None", "Null", "BooleanLiteral", "Into", "Keep", "With", @@ -349,13 +349,13 @@ const ( FqlLexerGte = 18 FqlLexerLte = 19 FqlLexerNeq = 20 - FqlLexerPlus = 21 - FqlLexerMinus = 22 - FqlLexerMinusMinus = 23 - FqlLexerPlusPlus = 24 - FqlLexerMulti = 25 - FqlLexerDiv = 26 - FqlLexerMod = 27 + FqlLexerMulti = 21 + FqlLexerDiv = 22 + FqlLexerMod = 23 + FqlLexerPlus = 24 + FqlLexerMinus = 25 + FqlLexerMinusMinus = 26 + FqlLexerPlusPlus = 27 FqlLexerAnd = 28 FqlLexerOr = 29 FqlLexerRange = 30 diff --git a/pkg/parser/fql/fql_parser.go b/pkg/parser/fql/fql_parser.go index a48b04ad..70683ee8 100644 --- a/pkg/parser/fql/fql_parser.go +++ b/pkg/parser/fql/fql_parser.go @@ -15,7 +15,7 @@ var _ = reflect.Copy var _ = strconv.Itoa var parserATN = []uint16{ - 3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 64, 545, + 3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 64, 554, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 4, 9, 9, 9, 4, 10, 9, 10, 4, 11, 9, 11, 4, 12, 9, 12, 4, 13, 9, 13, 4, 14, 9, 14, 4, 15, 9, 15, 4, 16, 9, 16, 4, 17, 9, 17, 4, 18, 9, @@ -25,249 +25,252 @@ var parserATN = []uint16{ 9, 34, 4, 35, 9, 35, 4, 36, 9, 36, 4, 37, 9, 37, 4, 38, 9, 38, 4, 39, 9, 39, 4, 40, 9, 40, 4, 41, 9, 41, 4, 42, 9, 42, 4, 43, 9, 43, 4, 44, 9, 44, 4, 45, 9, 45, 4, 46, 9, 46, 4, 47, 9, 47, 4, 48, 9, 48, 4, 49, 9, 49, 4, - 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 3, 2, - 3, 2, 3, 3, 7, 3, 112, 10, 3, 12, 3, 14, 3, 115, 11, 3, 3, 3, 3, 3, 3, - 4, 3, 4, 5, 4, 121, 10, 4, 3, 5, 3, 5, 5, 5, 125, 10, 5, 3, 6, 3, 6, 5, - 6, 129, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 134, 10, 6, 3, 6, 3, 6, 3, 6, 3, - 6, 3, 6, 3, 6, 5, 6, 142, 10, 6, 3, 7, 3, 7, 3, 7, 3, 7, 5, 7, 148, 10, - 7, 3, 7, 3, 7, 3, 7, 7, 7, 153, 10, 7, 12, 7, 14, 7, 156, 11, 7, 3, 7, - 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, 3, 10, - 3, 10, 5, 10, 171, 10, 10, 3, 11, 3, 11, 3, 11, 3, 11, 5, 11, 177, 10, - 11, 3, 12, 3, 12, 5, 12, 181, 10, 12, 3, 13, 3, 13, 5, 13, 185, 10, 13, - 3, 14, 3, 14, 5, 14, 189, 10, 14, 3, 15, 3, 15, 3, 15, 3, 16, 3, 16, 3, - 16, 3, 16, 5, 16, 198, 10, 16, 3, 17, 3, 17, 5, 17, 202, 10, 17, 3, 18, - 3, 18, 3, 18, 3, 18, 7, 18, 208, 10, 18, 12, 18, 14, 18, 211, 11, 18, 3, - 19, 3, 19, 5, 19, 215, 10, 19, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, - 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, - 20, 3, 20, 5, 20, 235, 10, 20, 3, 21, 3, 21, 3, 21, 3, 21, 3, 22, 3, 22, - 3, 22, 7, 22, 244, 10, 22, 12, 22, 14, 22, 247, 11, 22, 3, 23, 3, 23, 3, - 23, 3, 23, 7, 23, 253, 10, 23, 12, 23, 14, 23, 256, 11, 23, 3, 24, 3, 24, - 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 3, 25, 5, 25, 268, 10, - 25, 5, 25, 270, 10, 25, 3, 26, 3, 26, 3, 26, 3, 26, 3, 26, 3, 27, 3, 27, - 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, - 27, 3, 27, 3, 27, 5, 27, 292, 10, 27, 3, 28, 3, 28, 3, 28, 3, 29, 3, 29, - 3, 30, 3, 30, 3, 30, 5, 30, 302, 10, 30, 3, 30, 3, 30, 3, 30, 3, 30, 5, - 30, 308, 10, 30, 3, 31, 3, 31, 5, 31, 312, 10, 31, 3, 31, 3, 31, 3, 32, - 3, 32, 3, 32, 3, 32, 7, 32, 320, 10, 32, 12, 32, 14, 32, 323, 11, 32, 5, - 32, 325, 10, 32, 3, 32, 5, 32, 328, 10, 32, 3, 32, 3, 32, 3, 33, 3, 33, - 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, 37, 3, 37, 3, 38, 3, 38, 6, - 38, 344, 10, 38, 13, 38, 14, 38, 345, 3, 38, 7, 38, 349, 10, 38, 12, 38, - 14, 38, 352, 11, 38, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, - 39, 3, 39, 5, 39, 363, 10, 39, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 369, - 10, 40, 12, 40, 14, 40, 372, 11, 40, 6, 40, 374, 10, 40, 13, 40, 14, 40, - 375, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, 383, 10, 40, 12, 40, 14, - 40, 386, 11, 40, 7, 40, 388, 10, 40, 12, 40, 14, 40, 391, 11, 40, 3, 40, - 3, 40, 3, 40, 7, 40, 396, 10, 40, 12, 40, 14, 40, 399, 11, 40, 7, 40, 401, - 10, 40, 12, 40, 14, 40, 404, 11, 40, 5, 40, 406, 10, 40, 3, 41, 3, 41, - 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 5, 43, 416, 10, 43, 3, 44, 3, - 44, 3, 44, 7, 44, 421, 10, 44, 12, 44, 14, 44, 424, 11, 44, 3, 45, 3, 45, - 3, 45, 3, 46, 3, 46, 3, 46, 3, 46, 7, 46, 433, 10, 46, 12, 46, 14, 46, - 436, 11, 46, 5, 46, 438, 10, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, + 50, 9, 50, 4, 51, 9, 51, 4, 52, 9, 52, 4, 53, 9, 53, 4, 54, 9, 54, 4, 55, + 9, 55, 4, 56, 9, 56, 3, 2, 3, 2, 3, 3, 7, 3, 116, 10, 3, 12, 3, 14, 3, + 119, 11, 3, 3, 3, 3, 3, 3, 4, 3, 4, 5, 4, 125, 10, 4, 3, 5, 3, 5, 5, 5, + 129, 10, 5, 3, 6, 3, 6, 5, 6, 133, 10, 6, 3, 6, 3, 6, 3, 6, 5, 6, 138, + 10, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 5, 6, 146, 10, 6, 3, 7, 3, 7, + 3, 7, 3, 7, 5, 7, 152, 10, 7, 3, 7, 3, 7, 3, 7, 7, 7, 157, 10, 7, 12, 7, + 14, 7, 160, 11, 7, 3, 7, 3, 7, 3, 8, 3, 8, 3, 9, 3, 9, 3, 10, 3, 10, 3, + 10, 3, 10, 3, 10, 3, 10, 3, 10, 5, 10, 175, 10, 10, 3, 11, 3, 11, 3, 11, + 3, 11, 5, 11, 181, 10, 11, 3, 12, 3, 12, 5, 12, 185, 10, 12, 3, 13, 3, + 13, 5, 13, 189, 10, 13, 3, 14, 3, 14, 5, 14, 193, 10, 14, 3, 15, 3, 15, + 3, 15, 3, 16, 3, 16, 3, 16, 3, 16, 5, 16, 202, 10, 16, 3, 17, 3, 17, 5, + 17, 206, 10, 17, 3, 18, 3, 18, 3, 18, 3, 18, 7, 18, 212, 10, 18, 12, 18, + 14, 18, 215, 11, 18, 3, 19, 3, 19, 5, 19, 219, 10, 19, 3, 20, 3, 20, 3, + 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, + 3, 20, 3, 20, 3, 20, 3, 20, 3, 20, 5, 20, 239, 10, 20, 3, 21, 3, 21, 3, + 21, 3, 21, 3, 22, 3, 22, 3, 22, 7, 22, 248, 10, 22, 12, 22, 14, 22, 251, + 11, 22, 3, 23, 3, 23, 3, 23, 3, 23, 7, 23, 257, 10, 23, 12, 23, 14, 23, + 260, 11, 23, 3, 24, 3, 24, 3, 24, 3, 24, 3, 25, 3, 25, 3, 25, 3, 25, 3, + 25, 3, 25, 5, 25, 272, 10, 25, 5, 25, 274, 10, 25, 3, 26, 3, 26, 3, 26, + 3, 26, 3, 26, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, + 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 3, 27, 5, 27, 296, 10, 27, 3, 28, + 3, 28, 3, 28, 3, 29, 3, 29, 3, 30, 3, 30, 3, 30, 5, 30, 306, 10, 30, 3, + 30, 3, 30, 3, 30, 3, 30, 5, 30, 312, 10, 30, 3, 31, 3, 31, 5, 31, 316, + 10, 31, 3, 31, 3, 31, 3, 32, 3, 32, 3, 32, 3, 32, 7, 32, 324, 10, 32, 12, + 32, 14, 32, 327, 11, 32, 5, 32, 329, 10, 32, 3, 32, 5, 32, 332, 10, 32, + 3, 32, 3, 32, 3, 33, 3, 33, 3, 34, 3, 34, 3, 35, 3, 35, 3, 36, 3, 36, 3, + 37, 3, 37, 3, 38, 3, 38, 6, 38, 348, 10, 38, 13, 38, 14, 38, 349, 3, 38, + 7, 38, 353, 10, 38, 12, 38, 14, 38, 356, 11, 38, 3, 39, 3, 39, 3, 39, 3, + 39, 3, 39, 3, 39, 3, 39, 3, 39, 3, 39, 5, 39, 367, 10, 39, 3, 40, 3, 40, + 3, 40, 3, 40, 7, 40, 373, 10, 40, 12, 40, 14, 40, 376, 11, 40, 6, 40, 378, + 10, 40, 13, 40, 14, 40, 379, 3, 40, 3, 40, 3, 40, 3, 40, 3, 40, 7, 40, + 387, 10, 40, 12, 40, 14, 40, 390, 11, 40, 7, 40, 392, 10, 40, 12, 40, 14, + 40, 395, 11, 40, 3, 40, 3, 40, 3, 40, 7, 40, 400, 10, 40, 12, 40, 14, 40, + 403, 11, 40, 7, 40, 405, 10, 40, 12, 40, 14, 40, 408, 11, 40, 5, 40, 410, + 10, 40, 3, 41, 3, 41, 3, 42, 3, 42, 3, 42, 3, 42, 3, 43, 3, 43, 5, 43, + 420, 10, 43, 3, 44, 3, 44, 3, 44, 3, 44, 3, 45, 3, 45, 3, 45, 3, 46, 3, + 46, 3, 46, 3, 46, 7, 46, 433, 10, 46, 12, 46, 14, 46, 436, 11, 46, 5, 46, + 438, 10, 46, 3, 46, 3, 46, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, - 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 462, 10, 47, 3, 47, 3, - 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, - 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 480, 10, 47, 3, 47, 3, 47, 3, 47, 3, - 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 491, 10, 47, 3, 47, 3, 47, - 7, 47, 495, 10, 47, 12, 47, 14, 47, 498, 11, 47, 3, 48, 3, 48, 3, 48, 5, - 48, 503, 10, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, + 5, 47, 459, 10, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, + 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 473, 10, 47, 3, 47, 3, 47, 3, 47, + 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, + 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 3, 47, 5, 47, 496, 10, 47, + 3, 47, 3, 47, 7, 47, 500, 10, 47, 12, 47, 14, 47, 503, 11, 47, 3, 48, 3, + 48, 3, 48, 5, 48, 508, 10, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, - 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 528, 10, 48, 3, 49, 3, 49, 3, 50, - 3, 50, 3, 50, 5, 50, 535, 10, 50, 3, 51, 3, 51, 3, 52, 3, 52, 3, 53, 3, - 53, 3, 54, 3, 54, 3, 54, 2, 3, 92, 55, 2, 4, 6, 8, 10, 12, 14, 16, 18, - 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, - 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, - 92, 94, 96, 98, 100, 102, 104, 106, 2, 9, 3, 2, 61, 62, 3, 2, 46, 47, 4, - 2, 46, 46, 53, 54, 3, 2, 17, 22, 3, 2, 30, 31, 4, 2, 23, 24, 27, 29, 4, - 2, 23, 24, 56, 57, 2, 575, 2, 108, 3, 2, 2, 2, 4, 113, 3, 2, 2, 2, 6, 120, - 3, 2, 2, 2, 8, 124, 3, 2, 2, 2, 10, 141, 3, 2, 2, 2, 12, 143, 3, 2, 2, - 2, 14, 159, 3, 2, 2, 2, 16, 161, 3, 2, 2, 2, 18, 170, 3, 2, 2, 2, 20, 176, - 3, 2, 2, 2, 22, 180, 3, 2, 2, 2, 24, 184, 3, 2, 2, 2, 26, 188, 3, 2, 2, - 2, 28, 190, 3, 2, 2, 2, 30, 193, 3, 2, 2, 2, 32, 201, 3, 2, 2, 2, 34, 203, - 3, 2, 2, 2, 36, 212, 3, 2, 2, 2, 38, 234, 3, 2, 2, 2, 40, 236, 3, 2, 2, - 2, 42, 240, 3, 2, 2, 2, 44, 248, 3, 2, 2, 2, 46, 257, 3, 2, 2, 2, 48, 269, - 3, 2, 2, 2, 50, 271, 3, 2, 2, 2, 52, 291, 3, 2, 2, 2, 54, 293, 3, 2, 2, - 2, 56, 296, 3, 2, 2, 2, 58, 301, 3, 2, 2, 2, 60, 309, 3, 2, 2, 2, 62, 315, - 3, 2, 2, 2, 64, 331, 3, 2, 2, 2, 66, 333, 3, 2, 2, 2, 68, 335, 3, 2, 2, - 2, 70, 337, 3, 2, 2, 2, 72, 339, 3, 2, 2, 2, 74, 341, 3, 2, 2, 2, 76, 362, - 3, 2, 2, 2, 78, 405, 3, 2, 2, 2, 80, 407, 3, 2, 2, 2, 82, 409, 3, 2, 2, - 2, 84, 415, 3, 2, 2, 2, 86, 417, 3, 2, 2, 2, 88, 425, 3, 2, 2, 2, 90, 428, - 3, 2, 2, 2, 92, 461, 3, 2, 2, 2, 94, 527, 3, 2, 2, 2, 96, 529, 3, 2, 2, - 2, 98, 534, 3, 2, 2, 2, 100, 536, 3, 2, 2, 2, 102, 538, 3, 2, 2, 2, 104, - 540, 3, 2, 2, 2, 106, 542, 3, 2, 2, 2, 108, 109, 5, 4, 3, 2, 109, 3, 3, - 2, 2, 2, 110, 112, 5, 6, 4, 2, 111, 110, 3, 2, 2, 2, 112, 115, 3, 2, 2, - 2, 113, 111, 3, 2, 2, 2, 113, 114, 3, 2, 2, 2, 114, 116, 3, 2, 2, 2, 115, - 113, 3, 2, 2, 2, 116, 117, 5, 8, 5, 2, 117, 5, 3, 2, 2, 2, 118, 121, 5, - 88, 45, 2, 119, 121, 5, 52, 27, 2, 120, 118, 3, 2, 2, 2, 120, 119, 3, 2, - 2, 2, 121, 7, 3, 2, 2, 2, 122, 125, 5, 10, 6, 2, 123, 125, 5, 12, 7, 2, - 124, 122, 3, 2, 2, 2, 124, 123, 3, 2, 2, 2, 125, 9, 3, 2, 2, 2, 126, 128, - 7, 38, 2, 2, 127, 129, 7, 39, 2, 2, 128, 127, 3, 2, 2, 2, 128, 129, 3, - 2, 2, 2, 129, 130, 3, 2, 2, 2, 130, 142, 5, 92, 47, 2, 131, 133, 7, 38, - 2, 2, 132, 134, 7, 39, 2, 2, 133, 132, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, - 134, 135, 3, 2, 2, 2, 135, 136, 7, 13, 2, 2, 136, 137, 5, 12, 7, 2, 137, - 138, 7, 14, 2, 2, 138, 142, 3, 2, 2, 2, 139, 140, 7, 38, 2, 2, 140, 142, - 5, 94, 48, 2, 141, 126, 3, 2, 2, 2, 141, 131, 3, 2, 2, 2, 141, 139, 3, - 2, 2, 2, 142, 11, 3, 2, 2, 2, 143, 144, 7, 37, 2, 2, 144, 147, 5, 14, 8, - 2, 145, 146, 7, 10, 2, 2, 146, 148, 5, 16, 9, 2, 147, 145, 3, 2, 2, 2, - 147, 148, 3, 2, 2, 2, 148, 149, 3, 2, 2, 2, 149, 150, 7, 58, 2, 2, 150, - 154, 5, 18, 10, 2, 151, 153, 5, 24, 13, 2, 152, 151, 3, 2, 2, 2, 153, 156, - 3, 2, 2, 2, 154, 152, 3, 2, 2, 2, 154, 155, 3, 2, 2, 2, 155, 157, 3, 2, - 2, 2, 156, 154, 3, 2, 2, 2, 157, 158, 5, 26, 14, 2, 158, 13, 3, 2, 2, 2, - 159, 160, 7, 60, 2, 2, 160, 15, 3, 2, 2, 2, 161, 162, 7, 60, 2, 2, 162, - 17, 3, 2, 2, 2, 163, 171, 5, 88, 45, 2, 164, 171, 5, 60, 31, 2, 165, 171, - 5, 62, 32, 2, 166, 171, 5, 56, 29, 2, 167, 171, 5, 78, 40, 2, 168, 171, - 5, 58, 30, 2, 169, 171, 5, 54, 28, 2, 170, 163, 3, 2, 2, 2, 170, 164, 3, - 2, 2, 2, 170, 165, 3, 2, 2, 2, 170, 166, 3, 2, 2, 2, 170, 167, 3, 2, 2, - 2, 170, 168, 3, 2, 2, 2, 170, 169, 3, 2, 2, 2, 171, 19, 3, 2, 2, 2, 172, - 177, 5, 30, 16, 2, 173, 177, 5, 34, 18, 2, 174, 177, 5, 28, 15, 2, 175, - 177, 5, 38, 20, 2, 176, 172, 3, 2, 2, 2, 176, 173, 3, 2, 2, 2, 176, 174, - 3, 2, 2, 2, 176, 175, 3, 2, 2, 2, 177, 21, 3, 2, 2, 2, 178, 181, 5, 52, - 27, 2, 179, 181, 5, 88, 45, 2, 180, 178, 3, 2, 2, 2, 180, 179, 3, 2, 2, - 2, 181, 23, 3, 2, 2, 2, 182, 185, 5, 22, 12, 2, 183, 185, 5, 20, 11, 2, - 184, 182, 3, 2, 2, 2, 184, 183, 3, 2, 2, 2, 185, 25, 3, 2, 2, 2, 186, 189, - 5, 10, 6, 2, 187, 189, 5, 12, 7, 2, 188, 186, 3, 2, 2, 2, 188, 187, 3, - 2, 2, 2, 189, 27, 3, 2, 2, 2, 190, 191, 7, 40, 2, 2, 191, 192, 5, 92, 47, - 2, 192, 29, 3, 2, 2, 2, 193, 194, 7, 42, 2, 2, 194, 197, 5, 32, 17, 2, - 195, 196, 7, 10, 2, 2, 196, 198, 5, 32, 17, 2, 197, 195, 3, 2, 2, 2, 197, - 198, 3, 2, 2, 2, 198, 31, 3, 2, 2, 2, 199, 202, 7, 63, 2, 2, 200, 202, - 5, 54, 28, 2, 201, 199, 3, 2, 2, 2, 201, 200, 3, 2, 2, 2, 202, 33, 3, 2, - 2, 2, 203, 204, 7, 41, 2, 2, 204, 209, 5, 36, 19, 2, 205, 206, 7, 10, 2, - 2, 206, 208, 5, 36, 19, 2, 207, 205, 3, 2, 2, 2, 208, 211, 3, 2, 2, 2, - 209, 207, 3, 2, 2, 2, 209, 210, 3, 2, 2, 2, 210, 35, 3, 2, 2, 2, 211, 209, - 3, 2, 2, 2, 212, 214, 5, 92, 47, 2, 213, 215, 7, 45, 2, 2, 214, 213, 3, - 2, 2, 2, 214, 215, 3, 2, 2, 2, 215, 37, 3, 2, 2, 2, 216, 217, 7, 44, 2, - 2, 217, 235, 5, 50, 26, 2, 218, 219, 7, 44, 2, 2, 219, 235, 5, 44, 23, - 2, 220, 221, 7, 44, 2, 2, 221, 222, 5, 42, 22, 2, 222, 223, 5, 44, 23, - 2, 223, 235, 3, 2, 2, 2, 224, 225, 7, 44, 2, 2, 225, 226, 5, 42, 22, 2, - 226, 227, 5, 48, 25, 2, 227, 235, 3, 2, 2, 2, 228, 229, 7, 44, 2, 2, 229, - 230, 5, 42, 22, 2, 230, 231, 5, 50, 26, 2, 231, 235, 3, 2, 2, 2, 232, 233, - 7, 44, 2, 2, 233, 235, 5, 42, 22, 2, 234, 216, 3, 2, 2, 2, 234, 218, 3, - 2, 2, 2, 234, 220, 3, 2, 2, 2, 234, 224, 3, 2, 2, 2, 234, 228, 3, 2, 2, - 2, 234, 232, 3, 2, 2, 2, 235, 39, 3, 2, 2, 2, 236, 237, 7, 60, 2, 2, 237, - 238, 7, 33, 2, 2, 238, 239, 5, 92, 47, 2, 239, 41, 3, 2, 2, 2, 240, 245, - 5, 40, 21, 2, 241, 242, 7, 10, 2, 2, 242, 244, 5, 40, 21, 2, 243, 241, - 3, 2, 2, 2, 244, 247, 3, 2, 2, 2, 245, 243, 3, 2, 2, 2, 245, 246, 3, 2, - 2, 2, 246, 43, 3, 2, 2, 2, 247, 245, 3, 2, 2, 2, 248, 249, 7, 55, 2, 2, - 249, 254, 5, 46, 24, 2, 250, 251, 7, 10, 2, 2, 251, 253, 5, 46, 24, 2, - 252, 250, 3, 2, 2, 2, 253, 256, 3, 2, 2, 2, 254, 252, 3, 2, 2, 2, 254, - 255, 3, 2, 2, 2, 255, 45, 3, 2, 2, 2, 256, 254, 3, 2, 2, 2, 257, 258, 7, - 60, 2, 2, 258, 259, 7, 33, 2, 2, 259, 260, 5, 88, 45, 2, 260, 47, 3, 2, - 2, 2, 261, 262, 7, 49, 2, 2, 262, 270, 5, 40, 21, 2, 263, 264, 7, 49, 2, - 2, 264, 267, 7, 60, 2, 2, 265, 266, 7, 50, 2, 2, 266, 268, 7, 60, 2, 2, - 267, 265, 3, 2, 2, 2, 267, 268, 3, 2, 2, 2, 268, 270, 3, 2, 2, 2, 269, - 261, 3, 2, 2, 2, 269, 263, 3, 2, 2, 2, 270, 49, 3, 2, 2, 2, 271, 272, 7, - 51, 2, 2, 272, 273, 7, 52, 2, 2, 273, 274, 7, 49, 2, 2, 274, 275, 7, 60, - 2, 2, 275, 51, 3, 2, 2, 2, 276, 277, 7, 43, 2, 2, 277, 278, 7, 60, 2, 2, - 278, 279, 7, 33, 2, 2, 279, 292, 5, 92, 47, 2, 280, 281, 7, 43, 2, 2, 281, - 282, 7, 60, 2, 2, 282, 283, 7, 33, 2, 2, 283, 284, 7, 13, 2, 2, 284, 285, - 5, 12, 7, 2, 285, 286, 7, 14, 2, 2, 286, 292, 3, 2, 2, 2, 287, 288, 7, - 43, 2, 2, 288, 289, 7, 60, 2, 2, 289, 290, 7, 33, 2, 2, 290, 292, 5, 94, - 48, 2, 291, 276, 3, 2, 2, 2, 291, 280, 3, 2, 2, 2, 291, 287, 3, 2, 2, 2, - 292, 53, 3, 2, 2, 2, 293, 294, 7, 59, 2, 2, 294, 295, 7, 60, 2, 2, 295, - 55, 3, 2, 2, 2, 296, 297, 7, 60, 2, 2, 297, 57, 3, 2, 2, 2, 298, 302, 5, - 68, 35, 2, 299, 302, 5, 56, 29, 2, 300, 302, 5, 54, 28, 2, 301, 298, 3, - 2, 2, 2, 301, 299, 3, 2, 2, 2, 301, 300, 3, 2, 2, 2, 302, 303, 3, 2, 2, - 2, 303, 307, 7, 32, 2, 2, 304, 308, 5, 68, 35, 2, 305, 308, 5, 56, 29, - 2, 306, 308, 5, 54, 28, 2, 307, 304, 3, 2, 2, 2, 307, 305, 3, 2, 2, 2, - 307, 306, 3, 2, 2, 2, 308, 59, 3, 2, 2, 2, 309, 311, 7, 11, 2, 2, 310, - 312, 5, 74, 38, 2, 311, 310, 3, 2, 2, 2, 311, 312, 3, 2, 2, 2, 312, 313, - 3, 2, 2, 2, 313, 314, 7, 12, 2, 2, 314, 61, 3, 2, 2, 2, 315, 324, 7, 15, - 2, 2, 316, 321, 5, 76, 39, 2, 317, 318, 7, 10, 2, 2, 318, 320, 5, 76, 39, - 2, 319, 317, 3, 2, 2, 2, 320, 323, 3, 2, 2, 2, 321, 319, 3, 2, 2, 2, 321, - 322, 3, 2, 2, 2, 322, 325, 3, 2, 2, 2, 323, 321, 3, 2, 2, 2, 324, 316, - 3, 2, 2, 2, 324, 325, 3, 2, 2, 2, 325, 327, 3, 2, 2, 2, 326, 328, 7, 10, - 2, 2, 327, 326, 3, 2, 2, 2, 327, 328, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, - 329, 330, 7, 16, 2, 2, 330, 63, 3, 2, 2, 2, 331, 332, 7, 48, 2, 2, 332, - 65, 3, 2, 2, 2, 333, 334, 9, 2, 2, 2, 334, 67, 3, 2, 2, 2, 335, 336, 7, - 63, 2, 2, 336, 69, 3, 2, 2, 2, 337, 338, 7, 64, 2, 2, 338, 71, 3, 2, 2, - 2, 339, 340, 9, 3, 2, 2, 340, 73, 3, 2, 2, 2, 341, 350, 5, 92, 47, 2, 342, - 344, 7, 10, 2, 2, 343, 342, 3, 2, 2, 2, 344, 345, 3, 2, 2, 2, 345, 343, - 3, 2, 2, 2, 345, 346, 3, 2, 2, 2, 346, 347, 3, 2, 2, 2, 347, 349, 5, 92, - 47, 2, 348, 343, 3, 2, 2, 2, 349, 352, 3, 2, 2, 2, 350, 348, 3, 2, 2, 2, - 350, 351, 3, 2, 2, 2, 351, 75, 3, 2, 2, 2, 352, 350, 3, 2, 2, 2, 353, 354, - 5, 84, 43, 2, 354, 355, 7, 7, 2, 2, 355, 356, 5, 92, 47, 2, 356, 363, 3, - 2, 2, 2, 357, 358, 5, 82, 42, 2, 358, 359, 7, 7, 2, 2, 359, 360, 5, 92, - 47, 2, 360, 363, 3, 2, 2, 2, 361, 363, 5, 80, 41, 2, 362, 353, 3, 2, 2, - 2, 362, 357, 3, 2, 2, 2, 362, 361, 3, 2, 2, 2, 363, 77, 3, 2, 2, 2, 364, - 373, 7, 60, 2, 2, 365, 366, 7, 9, 2, 2, 366, 370, 5, 84, 43, 2, 367, 369, - 5, 82, 42, 2, 368, 367, 3, 2, 2, 2, 369, 372, 3, 2, 2, 2, 370, 368, 3, - 2, 2, 2, 370, 371, 3, 2, 2, 2, 371, 374, 3, 2, 2, 2, 372, 370, 3, 2, 2, - 2, 373, 365, 3, 2, 2, 2, 374, 375, 3, 2, 2, 2, 375, 373, 3, 2, 2, 2, 375, - 376, 3, 2, 2, 2, 376, 406, 3, 2, 2, 2, 377, 378, 7, 60, 2, 2, 378, 389, - 5, 82, 42, 2, 379, 380, 7, 9, 2, 2, 380, 384, 5, 84, 43, 2, 381, 383, 5, - 82, 42, 2, 382, 381, 3, 2, 2, 2, 383, 386, 3, 2, 2, 2, 384, 382, 3, 2, - 2, 2, 384, 385, 3, 2, 2, 2, 385, 388, 3, 2, 2, 2, 386, 384, 3, 2, 2, 2, - 387, 379, 3, 2, 2, 2, 388, 391, 3, 2, 2, 2, 389, 387, 3, 2, 2, 2, 389, - 390, 3, 2, 2, 2, 390, 402, 3, 2, 2, 2, 391, 389, 3, 2, 2, 2, 392, 397, - 5, 82, 42, 2, 393, 394, 7, 9, 2, 2, 394, 396, 5, 84, 43, 2, 395, 393, 3, - 2, 2, 2, 396, 399, 3, 2, 2, 2, 397, 395, 3, 2, 2, 2, 397, 398, 3, 2, 2, - 2, 398, 401, 3, 2, 2, 2, 399, 397, 3, 2, 2, 2, 400, 392, 3, 2, 2, 2, 401, - 404, 3, 2, 2, 2, 402, 400, 3, 2, 2, 2, 402, 403, 3, 2, 2, 2, 403, 406, - 3, 2, 2, 2, 404, 402, 3, 2, 2, 2, 405, 364, 3, 2, 2, 2, 405, 377, 3, 2, - 2, 2, 406, 79, 3, 2, 2, 2, 407, 408, 5, 56, 29, 2, 408, 81, 3, 2, 2, 2, - 409, 410, 7, 11, 2, 2, 410, 411, 5, 92, 47, 2, 411, 412, 7, 12, 2, 2, 412, - 83, 3, 2, 2, 2, 413, 416, 7, 60, 2, 2, 414, 416, 5, 66, 34, 2, 415, 413, - 3, 2, 2, 2, 415, 414, 3, 2, 2, 2, 416, 85, 3, 2, 2, 2, 417, 422, 5, 92, - 47, 2, 418, 419, 7, 10, 2, 2, 419, 421, 5, 92, 47, 2, 420, 418, 3, 2, 2, - 2, 421, 424, 3, 2, 2, 2, 422, 420, 3, 2, 2, 2, 422, 423, 3, 2, 2, 2, 423, - 87, 3, 2, 2, 2, 424, 422, 3, 2, 2, 2, 425, 426, 7, 60, 2, 2, 426, 427, - 5, 90, 46, 2, 427, 89, 3, 2, 2, 2, 428, 437, 7, 13, 2, 2, 429, 434, 5, - 92, 47, 2, 430, 431, 7, 10, 2, 2, 431, 433, 5, 92, 47, 2, 432, 430, 3, - 2, 2, 2, 433, 436, 3, 2, 2, 2, 434, 432, 3, 2, 2, 2, 434, 435, 3, 2, 2, - 2, 435, 438, 3, 2, 2, 2, 436, 434, 3, 2, 2, 2, 437, 429, 3, 2, 2, 2, 437, - 438, 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 440, 7, 14, 2, 2, 440, 91, - 3, 2, 2, 2, 441, 442, 8, 47, 1, 2, 442, 443, 5, 106, 54, 2, 443, 444, 5, - 92, 47, 22, 444, 462, 3, 2, 2, 2, 445, 462, 5, 88, 45, 2, 446, 447, 7, - 13, 2, 2, 447, 448, 5, 86, 44, 2, 448, 449, 7, 14, 2, 2, 449, 462, 3, 2, - 2, 2, 450, 462, 5, 58, 30, 2, 451, 462, 5, 66, 34, 2, 452, 462, 5, 68, - 35, 2, 453, 462, 5, 70, 36, 2, 454, 462, 5, 64, 33, 2, 455, 462, 5, 60, - 31, 2, 456, 462, 5, 62, 32, 2, 457, 462, 5, 56, 29, 2, 458, 462, 5, 78, - 40, 2, 459, 462, 5, 72, 37, 2, 460, 462, 5, 54, 28, 2, 461, 441, 3, 2, - 2, 2, 461, 445, 3, 2, 2, 2, 461, 446, 3, 2, 2, 2, 461, 450, 3, 2, 2, 2, - 461, 451, 3, 2, 2, 2, 461, 452, 3, 2, 2, 2, 461, 453, 3, 2, 2, 2, 461, - 454, 3, 2, 2, 2, 461, 455, 3, 2, 2, 2, 461, 456, 3, 2, 2, 2, 461, 457, - 3, 2, 2, 2, 461, 458, 3, 2, 2, 2, 461, 459, 3, 2, 2, 2, 461, 460, 3, 2, - 2, 2, 462, 496, 3, 2, 2, 2, 463, 464, 12, 21, 2, 2, 464, 465, 5, 100, 51, - 2, 465, 466, 5, 92, 47, 22, 466, 495, 3, 2, 2, 2, 467, 468, 12, 20, 2, - 2, 468, 469, 5, 102, 52, 2, 469, 470, 5, 92, 47, 21, 470, 495, 3, 2, 2, - 2, 471, 472, 12, 19, 2, 2, 472, 473, 5, 104, 53, 2, 473, 474, 5, 92, 47, - 20, 474, 495, 3, 2, 2, 2, 475, 476, 12, 16, 2, 2, 476, 479, 5, 96, 49, - 2, 477, 480, 5, 98, 50, 2, 478, 480, 5, 100, 51, 2, 479, 477, 3, 2, 2, - 2, 479, 478, 3, 2, 2, 2, 480, 481, 3, 2, 2, 2, 481, 482, 5, 92, 47, 17, - 482, 495, 3, 2, 2, 2, 483, 484, 12, 15, 2, 2, 484, 485, 5, 98, 50, 2, 485, - 486, 5, 92, 47, 16, 486, 495, 3, 2, 2, 2, 487, 488, 12, 14, 2, 2, 488, - 490, 7, 34, 2, 2, 489, 491, 5, 92, 47, 2, 490, 489, 3, 2, 2, 2, 490, 491, - 3, 2, 2, 2, 491, 492, 3, 2, 2, 2, 492, 493, 7, 7, 2, 2, 493, 495, 5, 92, - 47, 15, 494, 463, 3, 2, 2, 2, 494, 467, 3, 2, 2, 2, 494, 471, 3, 2, 2, - 2, 494, 475, 3, 2, 2, 2, 494, 483, 3, 2, 2, 2, 494, 487, 3, 2, 2, 2, 495, - 498, 3, 2, 2, 2, 496, 494, 3, 2, 2, 2, 496, 497, 3, 2, 2, 2, 497, 93, 3, - 2, 2, 2, 498, 496, 3, 2, 2, 2, 499, 500, 5, 92, 47, 2, 500, 502, 7, 34, - 2, 2, 501, 503, 5, 92, 47, 2, 502, 501, 3, 2, 2, 2, 502, 503, 3, 2, 2, - 2, 503, 504, 3, 2, 2, 2, 504, 505, 7, 7, 2, 2, 505, 506, 7, 13, 2, 2, 506, - 507, 5, 12, 7, 2, 507, 508, 7, 14, 2, 2, 508, 528, 3, 2, 2, 2, 509, 510, - 5, 92, 47, 2, 510, 511, 7, 34, 2, 2, 511, 512, 7, 13, 2, 2, 512, 513, 5, - 12, 7, 2, 513, 514, 7, 14, 2, 2, 514, 515, 7, 7, 2, 2, 515, 516, 5, 92, - 47, 2, 516, 528, 3, 2, 2, 2, 517, 518, 5, 92, 47, 2, 518, 519, 7, 34, 2, - 2, 519, 520, 7, 13, 2, 2, 520, 521, 5, 12, 7, 2, 521, 522, 7, 14, 2, 2, - 522, 523, 7, 7, 2, 2, 523, 524, 7, 13, 2, 2, 524, 525, 5, 12, 7, 2, 525, - 526, 7, 14, 2, 2, 526, 528, 3, 2, 2, 2, 527, 499, 3, 2, 2, 2, 527, 509, - 3, 2, 2, 2, 527, 517, 3, 2, 2, 2, 528, 95, 3, 2, 2, 2, 529, 530, 9, 4, - 2, 2, 530, 97, 3, 2, 2, 2, 531, 535, 7, 58, 2, 2, 532, 533, 7, 57, 2, 2, - 533, 535, 7, 58, 2, 2, 534, 531, 3, 2, 2, 2, 534, 532, 3, 2, 2, 2, 535, - 99, 3, 2, 2, 2, 536, 537, 9, 5, 2, 2, 537, 101, 3, 2, 2, 2, 538, 539, 9, - 6, 2, 2, 539, 103, 3, 2, 2, 2, 540, 541, 9, 7, 2, 2, 541, 105, 3, 2, 2, - 2, 542, 543, 9, 8, 2, 2, 543, 107, 3, 2, 2, 2, 53, 113, 120, 124, 128, - 133, 141, 147, 154, 170, 176, 180, 184, 188, 197, 201, 209, 214, 234, 245, - 254, 267, 269, 291, 301, 307, 311, 321, 324, 327, 345, 350, 362, 370, 375, - 384, 389, 397, 402, 405, 415, 422, 434, 437, 461, 479, 490, 494, 496, 502, - 527, 534, + 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 3, 48, 5, 48, 533, 10, 48, 3, 49, + 3, 49, 3, 50, 3, 50, 3, 50, 5, 50, 540, 10, 50, 3, 51, 3, 51, 3, 52, 3, + 52, 3, 53, 3, 53, 3, 54, 3, 54, 3, 55, 3, 55, 3, 56, 3, 56, 3, 56, 2, 3, + 92, 57, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, + 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, + 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, + 106, 108, 110, 2, 9, 3, 2, 61, 62, 3, 2, 46, 47, 4, 2, 46, 46, 53, 54, + 3, 2, 17, 22, 3, 2, 23, 25, 3, 2, 26, 27, 4, 2, 26, 27, 56, 57, 2, 583, + 2, 112, 3, 2, 2, 2, 4, 117, 3, 2, 2, 2, 6, 124, 3, 2, 2, 2, 8, 128, 3, + 2, 2, 2, 10, 145, 3, 2, 2, 2, 12, 147, 3, 2, 2, 2, 14, 163, 3, 2, 2, 2, + 16, 165, 3, 2, 2, 2, 18, 174, 3, 2, 2, 2, 20, 180, 3, 2, 2, 2, 22, 184, + 3, 2, 2, 2, 24, 188, 3, 2, 2, 2, 26, 192, 3, 2, 2, 2, 28, 194, 3, 2, 2, + 2, 30, 197, 3, 2, 2, 2, 32, 205, 3, 2, 2, 2, 34, 207, 3, 2, 2, 2, 36, 216, + 3, 2, 2, 2, 38, 238, 3, 2, 2, 2, 40, 240, 3, 2, 2, 2, 42, 244, 3, 2, 2, + 2, 44, 252, 3, 2, 2, 2, 46, 261, 3, 2, 2, 2, 48, 273, 3, 2, 2, 2, 50, 275, + 3, 2, 2, 2, 52, 295, 3, 2, 2, 2, 54, 297, 3, 2, 2, 2, 56, 300, 3, 2, 2, + 2, 58, 305, 3, 2, 2, 2, 60, 313, 3, 2, 2, 2, 62, 319, 3, 2, 2, 2, 64, 335, + 3, 2, 2, 2, 66, 337, 3, 2, 2, 2, 68, 339, 3, 2, 2, 2, 70, 341, 3, 2, 2, + 2, 72, 343, 3, 2, 2, 2, 74, 345, 3, 2, 2, 2, 76, 366, 3, 2, 2, 2, 78, 409, + 3, 2, 2, 2, 80, 411, 3, 2, 2, 2, 82, 413, 3, 2, 2, 2, 84, 419, 3, 2, 2, + 2, 86, 421, 3, 2, 2, 2, 88, 425, 3, 2, 2, 2, 90, 428, 3, 2, 2, 2, 92, 458, + 3, 2, 2, 2, 94, 532, 3, 2, 2, 2, 96, 534, 3, 2, 2, 2, 98, 539, 3, 2, 2, + 2, 100, 541, 3, 2, 2, 2, 102, 543, 3, 2, 2, 2, 104, 545, 3, 2, 2, 2, 106, + 547, 3, 2, 2, 2, 108, 549, 3, 2, 2, 2, 110, 551, 3, 2, 2, 2, 112, 113, + 5, 4, 3, 2, 113, 3, 3, 2, 2, 2, 114, 116, 5, 6, 4, 2, 115, 114, 3, 2, 2, + 2, 116, 119, 3, 2, 2, 2, 117, 115, 3, 2, 2, 2, 117, 118, 3, 2, 2, 2, 118, + 120, 3, 2, 2, 2, 119, 117, 3, 2, 2, 2, 120, 121, 5, 8, 5, 2, 121, 5, 3, + 2, 2, 2, 122, 125, 5, 88, 45, 2, 123, 125, 5, 52, 27, 2, 124, 122, 3, 2, + 2, 2, 124, 123, 3, 2, 2, 2, 125, 7, 3, 2, 2, 2, 126, 129, 5, 10, 6, 2, + 127, 129, 5, 12, 7, 2, 128, 126, 3, 2, 2, 2, 128, 127, 3, 2, 2, 2, 129, + 9, 3, 2, 2, 2, 130, 132, 7, 38, 2, 2, 131, 133, 7, 39, 2, 2, 132, 131, + 3, 2, 2, 2, 132, 133, 3, 2, 2, 2, 133, 134, 3, 2, 2, 2, 134, 146, 5, 92, + 47, 2, 135, 137, 7, 38, 2, 2, 136, 138, 7, 39, 2, 2, 137, 136, 3, 2, 2, + 2, 137, 138, 3, 2, 2, 2, 138, 139, 3, 2, 2, 2, 139, 140, 7, 13, 2, 2, 140, + 141, 5, 12, 7, 2, 141, 142, 7, 14, 2, 2, 142, 146, 3, 2, 2, 2, 143, 144, + 7, 38, 2, 2, 144, 146, 5, 94, 48, 2, 145, 130, 3, 2, 2, 2, 145, 135, 3, + 2, 2, 2, 145, 143, 3, 2, 2, 2, 146, 11, 3, 2, 2, 2, 147, 148, 7, 37, 2, + 2, 148, 151, 5, 14, 8, 2, 149, 150, 7, 10, 2, 2, 150, 152, 5, 16, 9, 2, + 151, 149, 3, 2, 2, 2, 151, 152, 3, 2, 2, 2, 152, 153, 3, 2, 2, 2, 153, + 154, 7, 58, 2, 2, 154, 158, 5, 18, 10, 2, 155, 157, 5, 24, 13, 2, 156, + 155, 3, 2, 2, 2, 157, 160, 3, 2, 2, 2, 158, 156, 3, 2, 2, 2, 158, 159, + 3, 2, 2, 2, 159, 161, 3, 2, 2, 2, 160, 158, 3, 2, 2, 2, 161, 162, 5, 26, + 14, 2, 162, 13, 3, 2, 2, 2, 163, 164, 7, 60, 2, 2, 164, 15, 3, 2, 2, 2, + 165, 166, 7, 60, 2, 2, 166, 17, 3, 2, 2, 2, 167, 175, 5, 88, 45, 2, 168, + 175, 5, 60, 31, 2, 169, 175, 5, 62, 32, 2, 170, 175, 5, 56, 29, 2, 171, + 175, 5, 78, 40, 2, 172, 175, 5, 58, 30, 2, 173, 175, 5, 54, 28, 2, 174, + 167, 3, 2, 2, 2, 174, 168, 3, 2, 2, 2, 174, 169, 3, 2, 2, 2, 174, 170, + 3, 2, 2, 2, 174, 171, 3, 2, 2, 2, 174, 172, 3, 2, 2, 2, 174, 173, 3, 2, + 2, 2, 175, 19, 3, 2, 2, 2, 176, 181, 5, 30, 16, 2, 177, 181, 5, 34, 18, + 2, 178, 181, 5, 28, 15, 2, 179, 181, 5, 38, 20, 2, 180, 176, 3, 2, 2, 2, + 180, 177, 3, 2, 2, 2, 180, 178, 3, 2, 2, 2, 180, 179, 3, 2, 2, 2, 181, + 21, 3, 2, 2, 2, 182, 185, 5, 52, 27, 2, 183, 185, 5, 88, 45, 2, 184, 182, + 3, 2, 2, 2, 184, 183, 3, 2, 2, 2, 185, 23, 3, 2, 2, 2, 186, 189, 5, 22, + 12, 2, 187, 189, 5, 20, 11, 2, 188, 186, 3, 2, 2, 2, 188, 187, 3, 2, 2, + 2, 189, 25, 3, 2, 2, 2, 190, 193, 5, 10, 6, 2, 191, 193, 5, 12, 7, 2, 192, + 190, 3, 2, 2, 2, 192, 191, 3, 2, 2, 2, 193, 27, 3, 2, 2, 2, 194, 195, 7, + 40, 2, 2, 195, 196, 5, 92, 47, 2, 196, 29, 3, 2, 2, 2, 197, 198, 7, 42, + 2, 2, 198, 201, 5, 32, 17, 2, 199, 200, 7, 10, 2, 2, 200, 202, 5, 32, 17, + 2, 201, 199, 3, 2, 2, 2, 201, 202, 3, 2, 2, 2, 202, 31, 3, 2, 2, 2, 203, + 206, 7, 63, 2, 2, 204, 206, 5, 54, 28, 2, 205, 203, 3, 2, 2, 2, 205, 204, + 3, 2, 2, 2, 206, 33, 3, 2, 2, 2, 207, 208, 7, 41, 2, 2, 208, 213, 5, 36, + 19, 2, 209, 210, 7, 10, 2, 2, 210, 212, 5, 36, 19, 2, 211, 209, 3, 2, 2, + 2, 212, 215, 3, 2, 2, 2, 213, 211, 3, 2, 2, 2, 213, 214, 3, 2, 2, 2, 214, + 35, 3, 2, 2, 2, 215, 213, 3, 2, 2, 2, 216, 218, 5, 92, 47, 2, 217, 219, + 7, 45, 2, 2, 218, 217, 3, 2, 2, 2, 218, 219, 3, 2, 2, 2, 219, 37, 3, 2, + 2, 2, 220, 221, 7, 44, 2, 2, 221, 239, 5, 50, 26, 2, 222, 223, 7, 44, 2, + 2, 223, 239, 5, 44, 23, 2, 224, 225, 7, 44, 2, 2, 225, 226, 5, 42, 22, + 2, 226, 227, 5, 44, 23, 2, 227, 239, 3, 2, 2, 2, 228, 229, 7, 44, 2, 2, + 229, 230, 5, 42, 22, 2, 230, 231, 5, 48, 25, 2, 231, 239, 3, 2, 2, 2, 232, + 233, 7, 44, 2, 2, 233, 234, 5, 42, 22, 2, 234, 235, 5, 50, 26, 2, 235, + 239, 3, 2, 2, 2, 236, 237, 7, 44, 2, 2, 237, 239, 5, 42, 22, 2, 238, 220, + 3, 2, 2, 2, 238, 222, 3, 2, 2, 2, 238, 224, 3, 2, 2, 2, 238, 228, 3, 2, + 2, 2, 238, 232, 3, 2, 2, 2, 238, 236, 3, 2, 2, 2, 239, 39, 3, 2, 2, 2, + 240, 241, 7, 60, 2, 2, 241, 242, 7, 33, 2, 2, 242, 243, 5, 92, 47, 2, 243, + 41, 3, 2, 2, 2, 244, 249, 5, 40, 21, 2, 245, 246, 7, 10, 2, 2, 246, 248, + 5, 40, 21, 2, 247, 245, 3, 2, 2, 2, 248, 251, 3, 2, 2, 2, 249, 247, 3, + 2, 2, 2, 249, 250, 3, 2, 2, 2, 250, 43, 3, 2, 2, 2, 251, 249, 3, 2, 2, + 2, 252, 253, 7, 55, 2, 2, 253, 258, 5, 46, 24, 2, 254, 255, 7, 10, 2, 2, + 255, 257, 5, 46, 24, 2, 256, 254, 3, 2, 2, 2, 257, 260, 3, 2, 2, 2, 258, + 256, 3, 2, 2, 2, 258, 259, 3, 2, 2, 2, 259, 45, 3, 2, 2, 2, 260, 258, 3, + 2, 2, 2, 261, 262, 7, 60, 2, 2, 262, 263, 7, 33, 2, 2, 263, 264, 5, 88, + 45, 2, 264, 47, 3, 2, 2, 2, 265, 266, 7, 49, 2, 2, 266, 274, 5, 40, 21, + 2, 267, 268, 7, 49, 2, 2, 268, 271, 7, 60, 2, 2, 269, 270, 7, 50, 2, 2, + 270, 272, 7, 60, 2, 2, 271, 269, 3, 2, 2, 2, 271, 272, 3, 2, 2, 2, 272, + 274, 3, 2, 2, 2, 273, 265, 3, 2, 2, 2, 273, 267, 3, 2, 2, 2, 274, 49, 3, + 2, 2, 2, 275, 276, 7, 51, 2, 2, 276, 277, 7, 52, 2, 2, 277, 278, 7, 49, + 2, 2, 278, 279, 7, 60, 2, 2, 279, 51, 3, 2, 2, 2, 280, 281, 7, 43, 2, 2, + 281, 282, 7, 60, 2, 2, 282, 283, 7, 33, 2, 2, 283, 296, 5, 92, 47, 2, 284, + 285, 7, 43, 2, 2, 285, 286, 7, 60, 2, 2, 286, 287, 7, 33, 2, 2, 287, 288, + 7, 13, 2, 2, 288, 289, 5, 12, 7, 2, 289, 290, 7, 14, 2, 2, 290, 296, 3, + 2, 2, 2, 291, 292, 7, 43, 2, 2, 292, 293, 7, 60, 2, 2, 293, 294, 7, 33, + 2, 2, 294, 296, 5, 94, 48, 2, 295, 280, 3, 2, 2, 2, 295, 284, 3, 2, 2, + 2, 295, 291, 3, 2, 2, 2, 296, 53, 3, 2, 2, 2, 297, 298, 7, 59, 2, 2, 298, + 299, 7, 60, 2, 2, 299, 55, 3, 2, 2, 2, 300, 301, 7, 60, 2, 2, 301, 57, + 3, 2, 2, 2, 302, 306, 5, 68, 35, 2, 303, 306, 5, 56, 29, 2, 304, 306, 5, + 54, 28, 2, 305, 302, 3, 2, 2, 2, 305, 303, 3, 2, 2, 2, 305, 304, 3, 2, + 2, 2, 306, 307, 3, 2, 2, 2, 307, 311, 7, 32, 2, 2, 308, 312, 5, 68, 35, + 2, 309, 312, 5, 56, 29, 2, 310, 312, 5, 54, 28, 2, 311, 308, 3, 2, 2, 2, + 311, 309, 3, 2, 2, 2, 311, 310, 3, 2, 2, 2, 312, 59, 3, 2, 2, 2, 313, 315, + 7, 11, 2, 2, 314, 316, 5, 74, 38, 2, 315, 314, 3, 2, 2, 2, 315, 316, 3, + 2, 2, 2, 316, 317, 3, 2, 2, 2, 317, 318, 7, 12, 2, 2, 318, 61, 3, 2, 2, + 2, 319, 328, 7, 15, 2, 2, 320, 325, 5, 76, 39, 2, 321, 322, 7, 10, 2, 2, + 322, 324, 5, 76, 39, 2, 323, 321, 3, 2, 2, 2, 324, 327, 3, 2, 2, 2, 325, + 323, 3, 2, 2, 2, 325, 326, 3, 2, 2, 2, 326, 329, 3, 2, 2, 2, 327, 325, + 3, 2, 2, 2, 328, 320, 3, 2, 2, 2, 328, 329, 3, 2, 2, 2, 329, 331, 3, 2, + 2, 2, 330, 332, 7, 10, 2, 2, 331, 330, 3, 2, 2, 2, 331, 332, 3, 2, 2, 2, + 332, 333, 3, 2, 2, 2, 333, 334, 7, 16, 2, 2, 334, 63, 3, 2, 2, 2, 335, + 336, 7, 48, 2, 2, 336, 65, 3, 2, 2, 2, 337, 338, 9, 2, 2, 2, 338, 67, 3, + 2, 2, 2, 339, 340, 7, 63, 2, 2, 340, 69, 3, 2, 2, 2, 341, 342, 7, 64, 2, + 2, 342, 71, 3, 2, 2, 2, 343, 344, 9, 3, 2, 2, 344, 73, 3, 2, 2, 2, 345, + 354, 5, 92, 47, 2, 346, 348, 7, 10, 2, 2, 347, 346, 3, 2, 2, 2, 348, 349, + 3, 2, 2, 2, 349, 347, 3, 2, 2, 2, 349, 350, 3, 2, 2, 2, 350, 351, 3, 2, + 2, 2, 351, 353, 5, 92, 47, 2, 352, 347, 3, 2, 2, 2, 353, 356, 3, 2, 2, + 2, 354, 352, 3, 2, 2, 2, 354, 355, 3, 2, 2, 2, 355, 75, 3, 2, 2, 2, 356, + 354, 3, 2, 2, 2, 357, 358, 5, 84, 43, 2, 358, 359, 7, 7, 2, 2, 359, 360, + 5, 92, 47, 2, 360, 367, 3, 2, 2, 2, 361, 362, 5, 82, 42, 2, 362, 363, 7, + 7, 2, 2, 363, 364, 5, 92, 47, 2, 364, 367, 3, 2, 2, 2, 365, 367, 5, 80, + 41, 2, 366, 357, 3, 2, 2, 2, 366, 361, 3, 2, 2, 2, 366, 365, 3, 2, 2, 2, + 367, 77, 3, 2, 2, 2, 368, 377, 7, 60, 2, 2, 369, 370, 7, 9, 2, 2, 370, + 374, 5, 84, 43, 2, 371, 373, 5, 82, 42, 2, 372, 371, 3, 2, 2, 2, 373, 376, + 3, 2, 2, 2, 374, 372, 3, 2, 2, 2, 374, 375, 3, 2, 2, 2, 375, 378, 3, 2, + 2, 2, 376, 374, 3, 2, 2, 2, 377, 369, 3, 2, 2, 2, 378, 379, 3, 2, 2, 2, + 379, 377, 3, 2, 2, 2, 379, 380, 3, 2, 2, 2, 380, 410, 3, 2, 2, 2, 381, + 382, 7, 60, 2, 2, 382, 393, 5, 82, 42, 2, 383, 384, 7, 9, 2, 2, 384, 388, + 5, 84, 43, 2, 385, 387, 5, 82, 42, 2, 386, 385, 3, 2, 2, 2, 387, 390, 3, + 2, 2, 2, 388, 386, 3, 2, 2, 2, 388, 389, 3, 2, 2, 2, 389, 392, 3, 2, 2, + 2, 390, 388, 3, 2, 2, 2, 391, 383, 3, 2, 2, 2, 392, 395, 3, 2, 2, 2, 393, + 391, 3, 2, 2, 2, 393, 394, 3, 2, 2, 2, 394, 406, 3, 2, 2, 2, 395, 393, + 3, 2, 2, 2, 396, 401, 5, 82, 42, 2, 397, 398, 7, 9, 2, 2, 398, 400, 5, + 84, 43, 2, 399, 397, 3, 2, 2, 2, 400, 403, 3, 2, 2, 2, 401, 399, 3, 2, + 2, 2, 401, 402, 3, 2, 2, 2, 402, 405, 3, 2, 2, 2, 403, 401, 3, 2, 2, 2, + 404, 396, 3, 2, 2, 2, 405, 408, 3, 2, 2, 2, 406, 404, 3, 2, 2, 2, 406, + 407, 3, 2, 2, 2, 407, 410, 3, 2, 2, 2, 408, 406, 3, 2, 2, 2, 409, 368, + 3, 2, 2, 2, 409, 381, 3, 2, 2, 2, 410, 79, 3, 2, 2, 2, 411, 412, 5, 56, + 29, 2, 412, 81, 3, 2, 2, 2, 413, 414, 7, 11, 2, 2, 414, 415, 5, 92, 47, + 2, 415, 416, 7, 12, 2, 2, 416, 83, 3, 2, 2, 2, 417, 420, 7, 60, 2, 2, 418, + 420, 5, 66, 34, 2, 419, 417, 3, 2, 2, 2, 419, 418, 3, 2, 2, 2, 420, 85, + 3, 2, 2, 2, 421, 422, 7, 13, 2, 2, 422, 423, 5, 92, 47, 2, 423, 424, 7, + 14, 2, 2, 424, 87, 3, 2, 2, 2, 425, 426, 7, 60, 2, 2, 426, 427, 5, 90, + 46, 2, 427, 89, 3, 2, 2, 2, 428, 437, 7, 13, 2, 2, 429, 434, 5, 92, 47, + 2, 430, 431, 7, 10, 2, 2, 431, 433, 5, 92, 47, 2, 432, 430, 3, 2, 2, 2, + 433, 436, 3, 2, 2, 2, 434, 432, 3, 2, 2, 2, 434, 435, 3, 2, 2, 2, 435, + 438, 3, 2, 2, 2, 436, 434, 3, 2, 2, 2, 437, 429, 3, 2, 2, 2, 437, 438, + 3, 2, 2, 2, 438, 439, 3, 2, 2, 2, 439, 440, 7, 14, 2, 2, 440, 91, 3, 2, + 2, 2, 441, 442, 8, 47, 1, 2, 442, 443, 5, 110, 56, 2, 443, 444, 5, 92, + 47, 24, 444, 459, 3, 2, 2, 2, 445, 459, 5, 88, 45, 2, 446, 459, 5, 86, + 44, 2, 447, 459, 5, 58, 30, 2, 448, 459, 5, 66, 34, 2, 449, 459, 5, 68, + 35, 2, 450, 459, 5, 70, 36, 2, 451, 459, 5, 64, 33, 2, 452, 459, 5, 60, + 31, 2, 453, 459, 5, 62, 32, 2, 454, 459, 5, 56, 29, 2, 455, 459, 5, 78, + 40, 2, 456, 459, 5, 72, 37, 2, 457, 459, 5, 54, 28, 2, 458, 441, 3, 2, + 2, 2, 458, 445, 3, 2, 2, 2, 458, 446, 3, 2, 2, 2, 458, 447, 3, 2, 2, 2, + 458, 448, 3, 2, 2, 2, 458, 449, 3, 2, 2, 2, 458, 450, 3, 2, 2, 2, 458, + 451, 3, 2, 2, 2, 458, 452, 3, 2, 2, 2, 458, 453, 3, 2, 2, 2, 458, 454, + 3, 2, 2, 2, 458, 455, 3, 2, 2, 2, 458, 456, 3, 2, 2, 2, 458, 457, 3, 2, + 2, 2, 459, 501, 3, 2, 2, 2, 460, 461, 12, 23, 2, 2, 461, 462, 5, 106, 54, + 2, 462, 463, 5, 92, 47, 24, 463, 500, 3, 2, 2, 2, 464, 465, 12, 22, 2, + 2, 465, 466, 5, 108, 55, 2, 466, 467, 5, 92, 47, 23, 467, 500, 3, 2, 2, + 2, 468, 469, 12, 19, 2, 2, 469, 472, 5, 96, 49, 2, 470, 473, 5, 98, 50, + 2, 471, 473, 5, 100, 51, 2, 472, 470, 3, 2, 2, 2, 472, 471, 3, 2, 2, 2, + 473, 474, 3, 2, 2, 2, 474, 475, 5, 92, 47, 20, 475, 500, 3, 2, 2, 2, 476, + 477, 12, 18, 2, 2, 477, 478, 5, 98, 50, 2, 478, 479, 5, 92, 47, 19, 479, + 500, 3, 2, 2, 2, 480, 481, 12, 17, 2, 2, 481, 482, 5, 100, 51, 2, 482, + 483, 5, 92, 47, 18, 483, 500, 3, 2, 2, 2, 484, 485, 12, 16, 2, 2, 485, + 486, 5, 102, 52, 2, 486, 487, 5, 92, 47, 17, 487, 500, 3, 2, 2, 2, 488, + 489, 12, 15, 2, 2, 489, 490, 5, 104, 53, 2, 490, 491, 5, 92, 47, 16, 491, + 500, 3, 2, 2, 2, 492, 493, 12, 14, 2, 2, 493, 495, 7, 34, 2, 2, 494, 496, + 5, 92, 47, 2, 495, 494, 3, 2, 2, 2, 495, 496, 3, 2, 2, 2, 496, 497, 3, + 2, 2, 2, 497, 498, 7, 7, 2, 2, 498, 500, 5, 92, 47, 15, 499, 460, 3, 2, + 2, 2, 499, 464, 3, 2, 2, 2, 499, 468, 3, 2, 2, 2, 499, 476, 3, 2, 2, 2, + 499, 480, 3, 2, 2, 2, 499, 484, 3, 2, 2, 2, 499, 488, 3, 2, 2, 2, 499, + 492, 3, 2, 2, 2, 500, 503, 3, 2, 2, 2, 501, 499, 3, 2, 2, 2, 501, 502, + 3, 2, 2, 2, 502, 93, 3, 2, 2, 2, 503, 501, 3, 2, 2, 2, 504, 505, 5, 92, + 47, 2, 505, 507, 7, 34, 2, 2, 506, 508, 5, 92, 47, 2, 507, 506, 3, 2, 2, + 2, 507, 508, 3, 2, 2, 2, 508, 509, 3, 2, 2, 2, 509, 510, 7, 7, 2, 2, 510, + 511, 7, 13, 2, 2, 511, 512, 5, 12, 7, 2, 512, 513, 7, 14, 2, 2, 513, 533, + 3, 2, 2, 2, 514, 515, 5, 92, 47, 2, 515, 516, 7, 34, 2, 2, 516, 517, 7, + 13, 2, 2, 517, 518, 5, 12, 7, 2, 518, 519, 7, 14, 2, 2, 519, 520, 7, 7, + 2, 2, 520, 521, 5, 92, 47, 2, 521, 533, 3, 2, 2, 2, 522, 523, 5, 92, 47, + 2, 523, 524, 7, 34, 2, 2, 524, 525, 7, 13, 2, 2, 525, 526, 5, 12, 7, 2, + 526, 527, 7, 14, 2, 2, 527, 528, 7, 7, 2, 2, 528, 529, 7, 13, 2, 2, 529, + 530, 5, 12, 7, 2, 530, 531, 7, 14, 2, 2, 531, 533, 3, 2, 2, 2, 532, 504, + 3, 2, 2, 2, 532, 514, 3, 2, 2, 2, 532, 522, 3, 2, 2, 2, 533, 95, 3, 2, + 2, 2, 534, 535, 9, 4, 2, 2, 535, 97, 3, 2, 2, 2, 536, 540, 7, 58, 2, 2, + 537, 538, 7, 57, 2, 2, 538, 540, 7, 58, 2, 2, 539, 536, 3, 2, 2, 2, 539, + 537, 3, 2, 2, 2, 540, 99, 3, 2, 2, 2, 541, 542, 9, 5, 2, 2, 542, 101, 3, + 2, 2, 2, 543, 544, 7, 30, 2, 2, 544, 103, 3, 2, 2, 2, 545, 546, 7, 31, + 2, 2, 546, 105, 3, 2, 2, 2, 547, 548, 9, 6, 2, 2, 548, 107, 3, 2, 2, 2, + 549, 550, 9, 7, 2, 2, 550, 109, 3, 2, 2, 2, 551, 552, 9, 8, 2, 2, 552, + 111, 3, 2, 2, 2, 52, 117, 124, 128, 132, 137, 145, 151, 158, 174, 180, + 184, 188, 192, 201, 205, 213, 218, 238, 249, 258, 271, 273, 295, 305, 311, + 315, 325, 328, 331, 349, 354, 366, 374, 379, 388, 393, 401, 406, 409, 419, + 434, 437, 458, 472, 495, 499, 501, 507, 532, 539, } var deserializer = antlr.NewATNDeserializer(nil) var deserializedATN = deserializer.DeserializeFromUInt16(parserATN) var literalNames = []string{ "", "", "", "", "", "':'", "';'", "'.'", "','", "'['", "']'", "'('", "')'", - "'{'", "'}'", "'>'", "'<'", "'=='", "'>='", "'<='", "'!='", "'+'", "'-'", - "'--'", "'++'", "'*'", "'/'", "'%'", "", "", "", "'='", "'?'", "'!~'", + "'{'", "'}'", "'>'", "'<'", "'=='", "'>='", "'<='", "'!='", "'*'", "'/'", + "'%'", "'+'", "'-'", "'--'", "'++'", "", "", "", "'='", "'?'", "'!~'", "'=~'", "'FOR'", "'RETURN'", "'DISTINCT'", "'FILTER'", "'SORT'", "'LIMIT'", "'LET'", "'COLLECT'", "", "'NONE'", "'NULL'", "", "'INTO'", "'KEEP'", "'WITH'", "'COUNT'", "'ALL'", "'ANY'", "'AGGREGATE'", "'LIKE'", "", "'IN'", "'@'", @@ -276,7 +279,7 @@ var symbolicNames = []string{ "", "MultiLineComment", "SingleLineComment", "WhiteSpaces", "LineTerminator", "Colon", "SemiColon", "Dot", "Comma", "OpenBracket", "CloseBracket", "OpenParen", "CloseParen", "OpenBrace", "CloseBrace", "Gt", "Lt", "Eq", "Gte", "Lte", - "Neq", "Plus", "Minus", "MinusMinus", "PlusPlus", "Multi", "Div", "Mod", + "Neq", "Multi", "Div", "Mod", "Plus", "Minus", "MinusMinus", "PlusPlus", "And", "Or", "Range", "Assign", "QuestionMark", "RegexNotMatch", "RegexMatch", "For", "Return", "Distinct", "Filter", "Sort", "Limit", "Let", "Collect", "SortDirection", "None", "Null", "BooleanLiteral", "Into", "Keep", "With", @@ -295,9 +298,10 @@ var ruleNames = []string{ "variable", "rangeOperator", "arrayLiteral", "objectLiteral", "booleanLiteral", "stringLiteral", "integerLiteral", "floatLiteral", "noneLiteral", "arrayElementList", "propertyAssignment", "memberExpression", "shorthandPropertyName", "computedPropertyName", - "propertyName", "expressionSequence", "functionCallExpression", "arguments", + "propertyName", "expressionGroup", "functionCallExpression", "arguments", "expression", "forTernaryExpression", "arrayOperator", "inOperator", "equalityOperator", - "logicalOperator", "mathOperator", "unaryOperator", + "logicalAndOperator", "logicalOrOperator", "multiplicativeOperator", "additiveOperator", + "unaryOperator", } var decisionToDFA = make([]*antlr.DFA, len(deserializedATN.DecisionToState)) @@ -348,13 +352,13 @@ const ( FqlParserGte = 18 FqlParserLte = 19 FqlParserNeq = 20 - FqlParserPlus = 21 - FqlParserMinus = 22 - FqlParserMinusMinus = 23 - FqlParserPlusPlus = 24 - FqlParserMulti = 25 - FqlParserDiv = 26 - FqlParserMod = 27 + FqlParserMulti = 21 + FqlParserDiv = 22 + FqlParserMod = 23 + FqlParserPlus = 24 + FqlParserMinus = 25 + FqlParserMinusMinus = 26 + FqlParserPlusPlus = 27 FqlParserAnd = 28 FqlParserOr = 29 FqlParserRange = 30 @@ -436,7 +440,7 @@ const ( FqlParserRULE_shorthandPropertyName = 39 FqlParserRULE_computedPropertyName = 40 FqlParserRULE_propertyName = 41 - FqlParserRULE_expressionSequence = 42 + FqlParserRULE_expressionGroup = 42 FqlParserRULE_functionCallExpression = 43 FqlParserRULE_arguments = 44 FqlParserRULE_expression = 45 @@ -444,9 +448,11 @@ const ( FqlParserRULE_arrayOperator = 47 FqlParserRULE_inOperator = 48 FqlParserRULE_equalityOperator = 49 - FqlParserRULE_logicalOperator = 50 - FqlParserRULE_mathOperator = 51 - FqlParserRULE_unaryOperator = 52 + FqlParserRULE_logicalAndOperator = 50 + FqlParserRULE_logicalOrOperator = 51 + FqlParserRULE_multiplicativeOperator = 52 + FqlParserRULE_additiveOperator = 53 + FqlParserRULE_unaryOperator = 54 ) // IProgramContext is an interface to support dynamic dispatch. @@ -549,7 +555,7 @@ func (p *FqlParser) Program() (localctx IProgramContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(106) + p.SetState(110) p.Body() } @@ -679,22 +685,22 @@ func (p *FqlParser) Body() (localctx IBodyContext) { }() p.EnterOuterAlt(localctx, 1) - p.SetState(111) + p.SetState(115) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) for _la == FqlParserLet || _la == FqlParserIdentifier { { - p.SetState(108) + p.SetState(112) p.BodyStatement() } - p.SetState(113) + p.SetState(117) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) } { - p.SetState(114) + p.SetState(118) p.BodyExpression() } @@ -809,21 +815,21 @@ func (p *FqlParser) BodyStatement() (localctx IBodyStatementContext) { } }() - p.SetState(118) + p.SetState(122) p.GetErrorHandler().Sync(p) switch p.GetTokenStream().LA(1) { case FqlParserIdentifier: p.EnterOuterAlt(localctx, 1) { - p.SetState(116) + p.SetState(120) p.FunctionCallExpression() } case FqlParserLet: p.EnterOuterAlt(localctx, 2) { - p.SetState(117) + p.SetState(121) p.VariableDeclaration() } @@ -942,21 +948,21 @@ func (p *FqlParser) BodyExpression() (localctx IBodyExpressionContext) { } }() - p.SetState(122) + p.SetState(126) p.GetErrorHandler().Sync(p) switch p.GetTokenStream().LA(1) { case FqlParserReturn: p.EnterOuterAlt(localctx, 1) { - p.SetState(120) + p.SetState(124) p.ReturnExpression() } case FqlParserFor: p.EnterOuterAlt(localctx, 2) { - p.SetState(121) + p.SetState(125) p.ForExpression() } @@ -1102,69 +1108,69 @@ func (p *FqlParser) ReturnExpression() (localctx IReturnExpressionContext) { } }() - p.SetState(139) + p.SetState(143) p.GetErrorHandler().Sync(p) switch p.GetInterpreter().AdaptivePredict(p.GetTokenStream(), 5, p.GetParserRuleContext()) { case 1: p.EnterOuterAlt(localctx, 1) { - p.SetState(124) + p.SetState(128) p.Match(FqlParserReturn) } - p.SetState(126) + p.SetState(130) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) if _la == FqlParserDistinct { { - p.SetState(125) + p.SetState(129) p.Match(FqlParserDistinct) } } { - p.SetState(128) + p.SetState(132) p.expression(0) } case 2: p.EnterOuterAlt(localctx, 2) { - p.SetState(129) + p.SetState(133) p.Match(FqlParserReturn) } - p.SetState(131) + p.SetState(135) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) if _la == FqlParserDistinct { { - p.SetState(130) + p.SetState(134) p.Match(FqlParserDistinct) } } { - p.SetState(133) + p.SetState(137) p.Match(FqlParserOpenParen) } { - p.SetState(134) + p.SetState(138) p.ForExpression() } { - p.SetState(135) + p.SetState(139) p.Match(FqlParserCloseParen) } case 3: p.EnterOuterAlt(localctx, 3) { - p.SetState(137) + p.SetState(141) p.Match(FqlParserReturn) } { - p.SetState(138) + p.SetState(142) p.ForTernaryExpression() } @@ -1339,52 +1345,52 @@ func (p *FqlParser) ForExpression() (localctx IForExpressionContext) { p.EnterOuterAlt(localctx, 1) { - p.SetState(141) + p.SetState(145) p.Match(FqlParserFor) } { - p.SetState(142) + p.SetState(146) p.ForExpressionValueVariable() } - p.SetState(145) + p.SetState(149) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) if _la == FqlParserComma { { - p.SetState(143) + p.SetState(147) p.Match(FqlParserComma) } { - p.SetState(144) + p.SetState(148) p.ForExpressionKeyVariable() } } { - p.SetState(147) + p.SetState(151) p.Match(FqlParserIn) } { - p.SetState(148) + p.SetState(152) p.ForExpressionSource() } - p.SetState(152) + p.SetState(156) p.GetErrorHandler().Sync(p) _la = p.GetTokenStream().LA(1) for ((_la-38)&-(0x1f+1)) == 0 && ((1<` would generate span containing the title. + HeaderTemplate String + // HTML template for the print footer. Should use the same format as the `headerTemplate`. + FooterTemplate String + // Whether or not to prefer page size as defined by css. + // Defaults to false, in which case the content will be scaled to fit the paper size. + PreferCSSPageSize Boolean + } + + HTMLScreenshotFormat string + + HTMLScreenshotParams struct { + X Float + Y Float + Width Float + Height Float + Format HTMLScreenshotFormat + Quality Int + } + + // HTMLNode is a HTML Node HTMLNode interface { core.Value @@ -39,11 +95,97 @@ type ( InnerTextBySelectorAll(selector String) *Array CountBySelector(selector String) Int + + ExistsBySelector(selector String) Boolean } + DHTMLNode interface { + HTMLNode + io.Closer + + Click() (Boolean, error) + + Input(value core.Value, delay Int) error + + Select(value *Array) (*Array, error) + + ScrollIntoView() error + + Hover() error + + WaitForClass(class String, timeout Int) error + } + + // HTMLDocument is a HTML Document HTMLDocument interface { HTMLNode URL() core.Value } + + // DHTMLDocument is a Dynamic HTML Document + DHTMLDocument interface { + HTMLDocument + io.Closer + + Navigate(url String, timeout Int) error + + NavigateBack(skip Int, timeout Int) (Boolean, error) + + NavigateForward(skip Int, timeout Int) (Boolean, error) + + ClickBySelector(selector String) (Boolean, error) + + ClickBySelectorAll(selector String) (Boolean, error) + + InputBySelector(selector String, value core.Value, delay Int) (Boolean, error) + + SelectBySelector(selector String, value *Array) (*Array, error) + + HoverBySelector(selector String) error + + PrintToPDF(params HTMLPDFParams) (Binary, error) + + CaptureScreenshot(params HTMLScreenshotParams) (Binary, error) + + ScrollTop() error + + ScrollBottom() error + + ScrollBySelector(selector String) error + + WaitForNavigation(timeout Int) error + + WaitForSelector(selector String, timeout Int) error + + WaitForClass(selector, class String, timeout Int) error + + WaitForClassAll(selector, class String, timeout Int) error + } ) + +func IsHTMLScreenshotFormatValid(format string) bool { + value := HTMLScreenshotFormat(format) + + return value == HTMLScreenshotFormatPNG || value == HTMLScreenshotFormatJPEG +} + +func NewDefaultHTMLPDFParams() HTMLPDFParams { + return HTMLPDFParams{ + Landscape: False, + DisplayHeaderFooter: False, + PrintBackground: False, + Scale: Float(1), + PaperWidth: Float(8.5), + PaperHeight: Float(11), + MarginTop: Float(0.4), + MarginBottom: Float(0.4), + MarginLeft: Float(0.4), + MarginRight: Float(0.4), + PageRanges: EmptyString, + IgnoreInvalidPageRanges: False, + HeaderTemplate: EmptyString, + FooterTemplate: EmptyString, + PreferCSSPageSize: False, + } +} diff --git a/pkg/stdlib/html/click.go b/pkg/stdlib/html/click.go index d5af7a10..eb976bd5 100644 --- a/pkg/stdlib/html/click.go +++ b/pkg/stdlib/html/click.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -28,7 +27,7 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) { return values.False, err } - el, ok := arg1.(*dynamic.HTMLElement) + el, ok := arg1.(values.DHTMLNode) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -47,7 +46,7 @@ func Click(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := arg1.(*dynamic.HTMLDocument) + doc, ok := arg1.(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/click_all.go b/pkg/stdlib/html/click_all.go index 04ab04a5..80b2c668 100644 --- a/pkg/stdlib/html/click_all.go +++ b/pkg/stdlib/html/click_all.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -28,7 +27,7 @@ func ClickAll(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := arg1.(*dynamic.HTMLDocument) + doc, ok := arg1.(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/document.go b/pkg/stdlib/html/document.go index 3da99222..97980d0f 100644 --- a/pkg/stdlib/html/document.go +++ b/pkg/stdlib/html/document.go @@ -2,27 +2,28 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html" + "github.com/MontFerret/ferret/pkg/drivers" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" "time" ) -type LoadDocumentArgs struct { - Dynamic bool +type DocumentLoadParams struct { + Dynamic values.Boolean Timeout time.Duration } -// Page loads a HTML document by a given url. +// Document loads a HTML document by a given url. // By default, loads a document by http call - resulted document does not support any interactions. // If passed "true" as a second argument, headless browser is used for loading the document which support interactions. // @param url (String) - Target url string. If passed "about:blank" for dynamic document - it will open an empty page. -// @param dynamicOrTimeout (Boolean|Int, optional) - If boolean value is passed, it indicates whether to use dynamic document. -// If integer values is passed it sets a custom timeout. -// @param timeout (Int, optional) - Sets a custom timeout. +// @param isDynamicOrParams (Boolean|DocumentLoadParams) - Either a boolean value that indicates whether to use dynamic page +// or an object with the following properties : +// dynamic (Boolean) - Optional, indicates whether to use dynamic page. +// timeout (Int) - Optional, Document load timeout. // @returns (HTMLDocument) - Returns loaded HTML document. func Document(ctx context.Context, args ...core.Value) (core.Value, error) { - err := core.ValidateArgs(args, 1, 3) + err := core.ValidateArgs(args, 1, 2) if err != nil { return values.None, err @@ -36,23 +37,35 @@ func Document(ctx context.Context, args ...core.Value) (core.Value, error) { url := args[0].(values.String) - params, err := parseLoadDocumentArgs(args) + var params DocumentLoadParams - if err != nil { - return values.None, err + if len(args) == 1 { + params = newDefaultDocLoadParams() + } else { + p, err := newDocLoadParams(args[1]) + + if err != nil { + return values.None, err + } + + params = p } - var drv html.Driver - ctx, cancel := context.WithTimeout(ctx, params.Timeout) defer cancel() - if params.Dynamic == false { - drv, err = html.FromContext(ctx, html.Static) - } else { - drv, err = html.FromContext(ctx, html.Dynamic) + if params.Dynamic { + drv, err := drivers.DynamicFrom(ctx) + + if err != nil { + return values.None, err + } + + return drv.GetDocument(ctx, url) } + drv, err := drivers.StaticFrom(ctx) + if err != nil { return values.None, err } @@ -60,39 +73,46 @@ func Document(ctx context.Context, args ...core.Value) (core.Value, error) { return drv.GetDocument(ctx, url) } -func parseLoadDocumentArgs(args []core.Value) (LoadDocumentArgs, error) { - res := LoadDocumentArgs{ +func newDefaultDocLoadParams() DocumentLoadParams { + return DocumentLoadParams{ + Dynamic: false, Timeout: time.Second * 30, } +} - if len(args) == 3 { - err := core.ValidateType(args[1], core.BooleanType) +func newDocLoadParams(arg core.Value) (DocumentLoadParams, error) { + res := newDefaultDocLoadParams() - if err != nil { + if err := core.ValidateType(arg, core.BooleanType, core.ObjectType); err != nil { + return res, err + } + + if arg.Type() == core.BooleanType { + res.Dynamic = arg.(values.Boolean) + + return res, nil + } + + obj := arg.(*values.Object) + + isDynamic, exists := obj.Get(values.NewString("dynamic")) + + if exists { + if err := core.ValidateType(isDynamic, core.BooleanType); err != nil { return res, err } - res.Dynamic = bool(args[1].(values.Boolean)) + res.Dynamic = isDynamic.(values.Boolean) + } - err = core.ValidateType(args[2], core.IntType) + timeout, exists := obj.Get(values.NewString("timeout")) - if err != nil { + if exists { + if err := core.ValidateType(timeout, core.IntType); err != nil { return res, err } - res.Timeout = time.Duration(args[2].(values.Int)) * time.Millisecond - } else if len(args) == 2 { - err := core.ValidateType(args[1], core.BooleanType, core.IntType) - - if err != nil { - return res, err - } - - if args[1].Type() == core.BooleanType { - res.Dynamic = bool(args[1].(values.Boolean)) - } else { - res.Timeout = time.Duration(args[1].(values.Int)) * time.Millisecond - } + res.Timeout = time.Duration(timeout.(values.Int)) + time.Millisecond } return res, nil diff --git a/pkg/stdlib/html/download.go b/pkg/stdlib/html/download.go new file mode 100644 index 00000000..0a991f55 --- /dev/null +++ b/pkg/stdlib/html/download.go @@ -0,0 +1,44 @@ +package html + +import ( + "context" + "io/ioutil" + "net/http" + + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" +) + +// Download a resource from the given URL. +// @param URL (String) - URL to download. +// @returns data (Binary) - Returns a base64 encoded string in binary format. +func Download(_ context.Context, args ...core.Value) (core.Value, error) { + err := core.ValidateArgs(args, 1, 1) + + if err != nil { + return values.None, err + } + + arg1 := args[0] + err = core.ValidateType(arg1, core.StringType) + + if err != nil { + return values.None, err + } + + resp, err := http.Get(arg1.String()) + + if err != nil { + return values.None, err + } + + defer resp.Body.Close() + + data, err := ioutil.ReadAll(resp.Body) + + if err != nil { + return values.None, err + } + + return values.NewBinary(data), nil +} diff --git a/pkg/stdlib/html/element_exists.go b/pkg/stdlib/html/element_exists.go new file mode 100644 index 00000000..62b3ebe4 --- /dev/null +++ b/pkg/stdlib/html/element_exists.go @@ -0,0 +1,22 @@ +package html + +import ( + "context" + + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" +) + +// ElementExists returns a boolean value indicating whether there is an element matched by selector. +// @param docOrEl (HTMLDocument|HTMLElement) - Parent document or element. +// @param selector (String) - CSS selector. +// @returns (Boolean) - A boolean value indicating whether there is an element matched by selector. +func ElementExists(_ context.Context, args ...core.Value) (core.Value, error) { + el, selector, err := queryArgs(args) + + if err != nil { + return values.None, err + } + + return el.ExistsBySelector(selector), nil +} diff --git a/pkg/stdlib/html/hover.go b/pkg/stdlib/html/hover.go index af82bccb..23a387f4 100644 --- a/pkg/stdlib/html/hover.go +++ b/pkg/stdlib/html/hover.go @@ -2,7 +2,7 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -33,7 +33,7 @@ func Hover(_ context.Context, args ...core.Value) (core.Value, error) { } // Document with a selector - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -45,7 +45,7 @@ func Hover(_ context.Context, args ...core.Value) (core.Value, error) { } // Element - el, ok := args[0].(*dynamic.HTMLElement) + el, ok := args[0].(values.DHTMLNode) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/input.go b/pkg/stdlib/html/input.go index be2e7441..fb0b2a63 100644 --- a/pkg/stdlib/html/input.go +++ b/pkg/stdlib/html/input.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -29,8 +28,8 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) { } switch args[0].(type) { - case *dynamic.HTMLDocument: - doc, ok := arg1.(*dynamic.HTMLDocument) + case values.DHTMLDocument: + doc, ok := arg1.(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -50,6 +49,7 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) { arg4 := args[3] err = core.ValidateType(arg4, core.IntType) + if err != nil { return values.False, err } @@ -58,8 +58,8 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) { } return doc.InputBySelector(arg2.(values.String), args[2], delay) - case *dynamic.HTMLElement: - el, ok := arg1.(*dynamic.HTMLElement) + case values.DHTMLNode: + el, ok := arg1.(values.DHTMLNode) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -71,6 +71,7 @@ func Input(_ context.Context, args ...core.Value) (core.Value, error) { arg3 := args[2] err = core.ValidateType(arg3, core.IntType) + if err != nil { return values.False, err } diff --git a/pkg/stdlib/html/lib.go b/pkg/stdlib/html/lib.go index f39d571b..ab48da3e 100644 --- a/pkg/stdlib/html/lib.go +++ b/pkg/stdlib/html/lib.go @@ -1,7 +1,10 @@ package html import ( + "context" + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" "github.com/pkg/errors" ) @@ -16,12 +19,13 @@ func NewLib() map[string]core.Function { "CLICK": Click, "CLICK_ALL": ClickAll, "DOCUMENT": Document, - "DOCUMENT_PARSE": DocumentParse, "DOWNLOAD": Download, "ELEMENT": Element, + "ELEMENT_EXISTS": ElementExists, "ELEMENTS": Elements, "ELEMENTS_COUNT": ElementsCount, "HOVER": Hover, + "HTML_PARSE": Parse, "INNER_HTML": InnerHTML, "INNER_HTML_ALL": InnerHTMLAll, "INNER_TEXT": InnerText, @@ -43,3 +47,31 @@ func NewLib() map[string]core.Function { "WAIT_NAVIGATION": WaitNavigation, } } + +func ValidateDocument(ctx context.Context, value core.Value) (core.Value, error) { + err := core.ValidateType(value, core.HTMLDocumentType, core.StringType) + if err != nil { + return values.None, err + } + + var doc values.DHTMLDocument + var ok bool + + if value.Type() == core.StringType { + buf, err := Document(ctx, value, values.NewBoolean(true)) + + if err != nil { + return values.None, err + } + + doc, ok = buf.(values.DHTMLDocument) + } else { + doc, ok = value.(values.DHTMLDocument) + } + + if !ok { + return nil, ErrNotDynamic + } + + return doc, nil +} diff --git a/pkg/stdlib/html/navigate.go b/pkg/stdlib/html/navigate.go index 0c8a5ca5..1ab2b892 100644 --- a/pkg/stdlib/html/navigate.go +++ b/pkg/stdlib/html/navigate.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -33,7 +32,7 @@ func Navigate(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/navigate_back.go b/pkg/stdlib/html/navigate_back.go index 736e6643..d67e59da 100644 --- a/pkg/stdlib/html/navigate_back.go +++ b/pkg/stdlib/html/navigate_back.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -28,7 +27,7 @@ func NavigateBack(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/navigate_forward.go b/pkg/stdlib/html/navigate_forward.go index 51863909..5c53f671 100644 --- a/pkg/stdlib/html/navigate_forward.go +++ b/pkg/stdlib/html/navigate_forward.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -28,7 +27,7 @@ func NavigateForward(_ context.Context, args ...core.Value) (core.Value, error) return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/pagination.go b/pkg/stdlib/html/pagination.go index 36a075e6..44cbafce 100644 --- a/pkg/stdlib/html/pagination.go +++ b/pkg/stdlib/html/pagination.go @@ -2,7 +2,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/collections" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" @@ -20,7 +19,7 @@ func Pagination(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -39,12 +38,12 @@ func Pagination(_ context.Context, args ...core.Value) (core.Value, error) { type ( Paging struct { - document *dynamic.HTMLDocument + document values.DHTMLDocument selector values.String } PagingIterator struct { - document *dynamic.HTMLDocument + document values.DHTMLDocument selector values.String pos values.Int } diff --git a/pkg/stdlib/html/document_parse.go b/pkg/stdlib/html/parse.go similarity index 61% rename from pkg/stdlib/html/document_parse.go rename to pkg/stdlib/html/parse.go index 90aaee8c..d8828802 100644 --- a/pkg/stdlib/html/document_parse.go +++ b/pkg/stdlib/html/parse.go @@ -3,17 +3,16 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html" - "github.com/MontFerret/ferret/pkg/html/static" + "github.com/MontFerret/ferret/pkg/drivers" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) -// DocumentParse parses a given HTML string and returns a HTML document. +// Parse parses a given HTML string and returns a HTML document. // Returned HTML document is always static. // @param html (String) - Target HTML string. // @returns (HTMLDocument) - Parsed HTML static document. -func DocumentParse(ctx context.Context, args ...core.Value) (core.Value, error) { +func Parse(ctx context.Context, args ...core.Value) (core.Value, error) { err := core.ValidateArgs(args, 1, 1) if err != nil { @@ -26,7 +25,7 @@ func DocumentParse(ctx context.Context, args ...core.Value) (core.Value, error) return values.None, err } - drv, err := html.FromContext(ctx, html.Static) + drv, err := drivers.StaticFrom(ctx) if err != nil { return values.None, err @@ -34,5 +33,5 @@ func DocumentParse(ctx context.Context, args ...core.Value) (core.Value, error) str := args[0].(values.String) - return drv.(*static.Driver).ParseDocument(ctx, str) + return drv.ParseDocument(ctx, str) } diff --git a/pkg/stdlib/html/blob.go b/pkg/stdlib/html/pdf.go similarity index 50% rename from pkg/stdlib/html/blob.go rename to pkg/stdlib/html/pdf.go index 7fb86ab9..1a8df97a 100644 --- a/pkg/stdlib/html/blob.go +++ b/pkg/stdlib/html/pdf.go @@ -3,172 +3,19 @@ package html import ( "context" "fmt" - "io/ioutil" - "net/http" "regexp" - "github.com/mafredri/cdp/protocol/page" - - "github.com/MontFerret/ferret/pkg/html/dynamic" - "github.com/MontFerret/ferret/pkg/runtime/values" - "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" ) -func ValidateDocument(ctx context.Context, value core.Value) (core.Value, error) { - err := core.ValidateType(value, core.HTMLDocumentType, core.StringType) - if err != nil { - return values.None, err - } - - var doc *dynamic.HTMLDocument - var ok bool - if value.Type() == core.StringType { - buf, err := Document(ctx, value, values.NewBoolean(true)) - if err != nil { - return values.None, err - } - doc, ok = buf.(*dynamic.HTMLDocument) - } else { - doc, ok = value.(*dynamic.HTMLDocument) - } - - if !ok { - return nil, core.Error(core.ErrInvalidType, "expected dynamic document") - } - - return doc, nil -} - -// Screenshot take a screenshot of the current page. -// @param source (Document) - Document. -// @param params (Object) - Optional, An object containing the following properties : -// x (Float|Int) - Optional, X position of the viewport. -// x (Float|Int) - Optional,Y position of the viewport. -// width (Float|Int) - Optional, Width of the viewport. -// height (Float|Int) - Optional, Height of the viewport. -// format (String) - Optional, Either "jpeg" or "png". -// quality (Int) - Optional, Quality, in [0, 100], only for jpeg format. -// @returns data (Binary) - Returns a base64 encoded string in binary format. -func Screenshot(ctx context.Context, args ...core.Value) (core.Value, error) { - err := core.ValidateArgs(args, 1, 2) - if err != nil { - return values.None, err - } - - arg1 := args[0] - - err = core.ValidateType(arg1, core.HTMLDocumentType, core.StringType) - if err != nil { - return values.None, err - } - - val, err := ValidateDocument(ctx, arg1) - if err != nil { - return values.None, err - } - doc := val.(*dynamic.HTMLDocument) - defer doc.Close() - - screenshotParams := &dynamic.ScreenshotArgs{ - X: 0, - Y: 0, - Width: -1, - Height: -1, - Format: "jpeg", - Quality: 100, - } - if len(args) == 2 { - arg2 := args[1] - err = core.ValidateType(arg2, core.ObjectType) - if err != nil { - return values.None, err - } - params, ok := arg2.(*values.Object) - if !ok { - return values.None, core.Error(core.ErrInvalidType, "expected object") - } - - format, found := params.Get("format") - if found { - err = core.ValidateType(format, core.StringType) - if err != nil { - return values.None, err - } - if !dynamic.IsScreenshotFormatValid(format.String()) { - return values.None, core.Error( - core.ErrInvalidArgument, - fmt.Sprintf("format is not valid, expected jpeg or png, but got %s", format.String())) - } - screenshotParams.Format = dynamic.ScreenshotFormat(format.String()) - } - x, found := params.Get("x") - if found { - err = core.ValidateType(x, core.FloatType, core.IntType) - if err != nil { - return values.None, err - } - if x.Type() == core.IntType { - x = values.Float(x.(values.Int)) - } - screenshotParams.X = x.Unwrap().(float64) - } - y, found := params.Get("y") - if found { - err = core.ValidateType(y, core.FloatType, core.IntType) - if err != nil { - return values.None, err - } - if y.Type() == core.IntType { - y = values.Float(y.(values.Int)) - } - screenshotParams.Y = y.Unwrap().(float64) - } - width, found := params.Get("width") - if found { - err = core.ValidateType(width, core.FloatType, core.IntType) - if err != nil { - return values.None, err - } - if width.Type() == core.IntType { - width = values.Float(width.(values.Int)) - } - screenshotParams.Width = width.Unwrap().(float64) - } - height, found := params.Get("height") - if found { - err = core.ValidateType(height, core.FloatType, core.IntType) - if err != nil { - return values.None, err - } - if height.Type() == core.IntType { - height = values.Float(height.(values.Int)) - } - screenshotParams.Height = height.Unwrap().(float64) - } - quality, found := params.Get("quality") - if found { - err = core.ValidateType(quality, core.IntType) - if err != nil { - return values.None, err - } - screenshotParams.Quality = quality.Unwrap().(int) - } - } - - scr, err := doc.CaptureScreenshot(screenshotParams) - if err != nil { - return values.None, err - } - - return scr, nil -} - func ValidatePageRanges(pageRanges string) (bool, error) { match, err := regexp.Match(`^(([1-9][0-9]*|[1-9][0-9]*)(\s*-\s*|\s*,\s*|))*$`, []byte(pageRanges)) + if err != nil { return false, err } + return match, nil } @@ -193,211 +40,261 @@ func ValidatePageRanges(pageRanges string) (bool, error) { // @returns data (Binary) - Returns a base64 encoded string in binary format. func PDF(ctx context.Context, args ...core.Value) (core.Value, error) { err := core.ValidateArgs(args, 1, 2) + if err != nil { return values.None, err } arg1 := args[0] val, err := ValidateDocument(ctx, arg1) + if err != nil { return values.None, err } - doc := val.(*dynamic.HTMLDocument) + + doc := val.(values.DHTMLDocument) defer doc.Close() - pdfParams := page.NewPrintToPDFArgs() + pdfParams := values.HTMLPDFParams{} if len(args) == 2 { arg2 := args[1] err = core.ValidateType(arg2, core.ObjectType) + if err != nil { return values.None, err } + params, ok := arg2.(*values.Object) + if !ok { return values.None, core.Error(core.ErrInvalidType, "expected object") } landscape, found := params.Get("landscape") + if found { err = core.ValidateType(landscape, core.BooleanType) + if err != nil { return values.None, err } - pdfParams.SetLandscape(landscape.Unwrap().(bool)) + + pdfParams.Landscape = landscape.(values.Boolean) } + displayHeaderFooter, found := params.Get("displayHeaderFooter") + if found { err = core.ValidateType(displayHeaderFooter, core.BooleanType) + if err != nil { return values.None, err } - pdfParams.SetDisplayHeaderFooter(displayHeaderFooter.Unwrap().(bool)) + + pdfParams.DisplayHeaderFooter = displayHeaderFooter.(values.Boolean) } + printBackground, found := params.Get("printBackground") + if found { err = core.ValidateType(printBackground, core.BooleanType) + if err != nil { return values.None, err } - pdfParams.SetPrintBackground(printBackground.Unwrap().(bool)) + + pdfParams.PrintBackground = printBackground.(values.Boolean) } + scale, found := params.Get("scale") + if found { err = core.ValidateType(scale, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if scale.Type() == core.IntType { - scale = values.Float(scale.(values.Int)) + pdfParams.Scale = values.Float(scale.(values.Int)) + } else { + pdfParams.Scale = scale.(values.Float) } - pdfParams.SetScale(scale.Unwrap().(float64)) } + paperWidth, found := params.Get("paperWidth") + if found { err = core.ValidateType(paperWidth, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if paperWidth.Type() == core.IntType { - paperWidth = values.Float(paperWidth.(values.Int)) + pdfParams.PaperWidth = values.Float(paperWidth.(values.Int)) + } else { + pdfParams.PaperWidth = paperWidth.(values.Float) } - pdfParams.SetPaperWidth(paperWidth.Unwrap().(float64)) } + paperHeight, found := params.Get("paperHeight") + if found { err = core.ValidateType(paperHeight, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if paperHeight.Type() == core.IntType { - paperHeight = values.Float(paperHeight.(values.Int)) + pdfParams.PaperHeight = values.Float(paperHeight.(values.Int)) + } else { + pdfParams.PaperHeight = paperHeight.(values.Float) } - pdfParams.SetPaperHeight(paperHeight.Unwrap().(float64)) } + marginTop, found := params.Get("marginTop") + if found { err = core.ValidateType(marginTop, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if marginTop.Type() == core.IntType { - marginTop = values.Float(marginTop.(values.Int)) + pdfParams.MarginTop = values.Float(marginTop.(values.Int)) + } else { + pdfParams.MarginTop = marginTop.(values.Float) } - pdfParams.SetMarginTop(marginTop.Unwrap().(float64)) } + marginBottom, found := params.Get("marginBottom") + if found { err = core.ValidateType(marginBottom, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if marginBottom.Type() == core.IntType { - marginBottom = values.Float(marginBottom.(values.Int)) + pdfParams.MarginBottom = values.Float(marginBottom.(values.Int)) + } else { + pdfParams.MarginBottom = marginBottom.(values.Float) } - pdfParams.SetMarginBottom(marginBottom.Unwrap().(float64)) } + marginLeft, found := params.Get("marginLeft") + if found { err = core.ValidateType(marginLeft, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if marginLeft.Type() == core.IntType { - marginLeft = values.Float(marginLeft.(values.Int)) + pdfParams.MarginLeft = values.Float(marginLeft.(values.Int)) + } else { + pdfParams.MarginLeft = marginLeft.(values.Float) } - pdfParams.SetMarginLeft(marginLeft.Unwrap().(float64)) } + marginRight, found := params.Get("marginRight") + if found { err = core.ValidateType(marginRight, core.FloatType, core.IntType) + if err != nil { return values.None, err } + if marginRight.Type() == core.IntType { - marginRight = values.Float(marginRight.(values.Int)) + pdfParams.MarginRight = values.Float(marginRight.(values.Int)) + } else { + pdfParams.MarginRight = marginRight.(values.Float) } - pdfParams.SetMarginRight(marginRight.Unwrap().(float64)) } + pageRanges, found := params.Get("pageRanges") + if found { err = core.ValidateType(pageRanges, core.StringType) + if err != nil { return values.None, err } + validate, err := ValidatePageRanges(pageRanges.String()) + if err != nil { return values.None, err } + if !validate { return values.None, core.Error(core.ErrInvalidArgument, fmt.Sprintf(`page ranges "%s", not valid`, pageRanges.String())) } - pdfParams.SetPageRanges(pageRanges.String()) + + pdfParams.PageRanges = pageRanges.(values.String) } + ignoreInvalidPageRanges, found := params.Get("ignoreInvalidPageRanges") + if found { err = core.ValidateType(ignoreInvalidPageRanges, core.BooleanType) + if err != nil { return values.None, err } - pdfParams.SetIgnoreInvalidPageRanges(ignoreInvalidPageRanges.Unwrap().(bool)) + + pdfParams.IgnoreInvalidPageRanges = ignoreInvalidPageRanges.(values.Boolean) } + headerTemplate, found := params.Get("headerTemplate") + if found { err = core.ValidateType(headerTemplate, core.StringType) + if err != nil { return values.None, err } - pdfParams.SetHeaderTemplate(headerTemplate.String()) + + pdfParams.HeaderTemplate = headerTemplate.(values.String) } + footerTemplate, found := params.Get("footerTemplate") + if found { err = core.ValidateType(footerTemplate, core.StringType) + if err != nil { return values.None, err } - pdfParams.SetFooterTemplate(footerTemplate.String()) + + pdfParams.FooterTemplate = footerTemplate.(values.String) } + preferCSSPageSize, found := params.Get("preferCSSPageSize") + if found { err = core.ValidateType(preferCSSPageSize, core.BooleanType) + if err != nil { return values.None, err } - pdfParams.SetPreferCSSPageSize(preferCSSPageSize.Unwrap().(bool)) + + pdfParams.PreferCSSPageSize = preferCSSPageSize.(values.Boolean) } } pdf, err := doc.PrintToPDF(pdfParams) + if err != nil { return values.None, err } return pdf, nil } - -// Download a ressource from the given URL. -// @param URL (String) - URL to download. -// @returns data (Binary) - Returns a base64 encoded string in binary format. -func Download(_ context.Context, args ...core.Value) (core.Value, error) { - err := core.ValidateArgs(args, 1, 1) - if err != nil { - return values.None, err - } - - arg1 := args[0] - err = core.ValidateType(arg1, core.StringType) - if err != nil { - return values.None, err - } - resp, err := http.Get(arg1.String()) - if err != nil { - return values.None, err - } - defer resp.Body.Close() - data, err := ioutil.ReadAll(resp.Body) - if err != nil { - return values.None, err - } - return values.NewBinary(data), nil -} diff --git a/pkg/stdlib/html/screenshot.go b/pkg/stdlib/html/screenshot.go new file mode 100644 index 00000000..7ae8add2 --- /dev/null +++ b/pkg/stdlib/html/screenshot.go @@ -0,0 +1,163 @@ +package html + +import ( + "context" + "fmt" + + "github.com/MontFerret/ferret/pkg/runtime/core" + "github.com/MontFerret/ferret/pkg/runtime/values" +) + +// Screenshot takes a screenshot of the current page. +// @param source (Document) - Document. +// @param params (Object) - Optional, An object containing the following properties : +// x (Float|Int) - Optional, X position of the viewport. +// x (Float|Int) - Optional,Y position of the viewport. +// width (Float|Int) - Optional, Width of the viewport. +// height (Float|Int) - Optional, Height of the viewport. +// format (String) - Optional, Either "jpeg" or "png". +// quality (Int) - Optional, Quality, in [0, 100], only for jpeg format. +// @returns data (Binary) - Returns a base64 encoded string in binary format. +func Screenshot(ctx context.Context, args ...core.Value) (core.Value, error) { + err := core.ValidateArgs(args, 1, 2) + + if err != nil { + return values.None, err + } + + arg1 := args[0] + + err = core.ValidateType(arg1, core.HTMLDocumentType, core.StringType) + + if err != nil { + return values.None, err + } + + val, err := ValidateDocument(ctx, arg1) + + if err != nil { + return values.None, err + } + + doc := val.(values.DHTMLDocument) + + defer doc.Close() + + screenshotParams := values.HTMLScreenshotParams{ + X: 0, + Y: 0, + Width: -1, + Height: -1, + Format: values.HTMLScreenshotFormatJPEG, + Quality: 100, + } + + if len(args) == 2 { + arg2 := args[1] + err = core.ValidateType(arg2, core.ObjectType) + + if err != nil { + return values.None, err + } + + params, ok := arg2.(*values.Object) + + if !ok { + return values.None, core.Error(core.ErrInvalidType, "expected object") + } + + format, found := params.Get("format") + + if found { + err = core.ValidateType(format, core.StringType) + + if err != nil { + return values.None, err + } + + if !values.IsHTMLScreenshotFormatValid(format.String()) { + return values.None, core.Error( + core.ErrInvalidArgument, + fmt.Sprintf("format is not valid, expected jpeg or png, but got %s", format.String())) + } + + screenshotParams.Format = values.HTMLScreenshotFormat(format.String()) + } + + x, found := params.Get("x") + + if found { + err = core.ValidateType(x, core.FloatType, core.IntType) + + if err != nil { + return values.None, err + } + + if x.Type() == core.IntType { + screenshotParams.X = values.Float(x.(values.Int)) + } + } + + y, found := params.Get("y") + + if found { + err = core.ValidateType(y, core.FloatType, core.IntType) + + if err != nil { + return values.None, err + } + + if y.Type() == core.IntType { + screenshotParams.Y = values.Float(y.(values.Int)) + } + } + + width, found := params.Get("width") + + if found { + err = core.ValidateType(width, core.FloatType, core.IntType) + + if err != nil { + return values.None, err + } + + if width.Type() == core.IntType { + screenshotParams.Width = values.Float(width.(values.Int)) + } + } + + height, found := params.Get("height") + + if found { + err = core.ValidateType(height, core.FloatType, core.IntType) + + if err != nil { + return values.None, err + } + + if height.Type() == core.IntType { + screenshotParams.Height = values.Float(height.(values.Int)) + } + } + + quality, found := params.Get("quality") + + if found { + err = core.ValidateType(quality, core.IntType) + + if err != nil { + return values.None, err + } + + screenshotParams.Quality = quality.(values.Int) + } + } + + scr, err := doc.CaptureScreenshot(screenshotParams) + + if err != nil { + return values.None, err + } + + return scr, nil +} diff --git a/pkg/stdlib/html/scroll_bottom.go b/pkg/stdlib/html/scroll_bottom.go index 7bce0085..76721b0a 100644 --- a/pkg/stdlib/html/scroll_bottom.go +++ b/pkg/stdlib/html/scroll_bottom.go @@ -2,7 +2,7 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -22,7 +22,7 @@ func ScrollBottom(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/scroll_element.go b/pkg/stdlib/html/scroll_element.go index 88ea3286..44e460d0 100644 --- a/pkg/stdlib/html/scroll_element.go +++ b/pkg/stdlib/html/scroll_element.go @@ -2,7 +2,7 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -32,7 +32,7 @@ func ScrollInto(_ context.Context, args ...core.Value) (core.Value, error) { } // Document with a selector - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -44,7 +44,7 @@ func ScrollInto(_ context.Context, args ...core.Value) (core.Value, error) { } // Element - el, ok := args[0].(*dynamic.HTMLElement) + el, ok := args[0].(values.DHTMLNode) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/scroll_top.go b/pkg/stdlib/html/scroll_top.go index 3cab8a01..d06eb6f6 100644 --- a/pkg/stdlib/html/scroll_top.go +++ b/pkg/stdlib/html/scroll_top.go @@ -2,7 +2,7 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -22,7 +22,7 @@ func ScrollTop(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/select.go b/pkg/stdlib/html/select.go index ea318c50..a4db6444 100644 --- a/pkg/stdlib/html/select.go +++ b/pkg/stdlib/html/select.go @@ -2,7 +2,7 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" + "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -27,8 +27,8 @@ func Select(_ context.Context, args ...core.Value) (core.Value, error) { } switch args[0].(type) { - case *dynamic.HTMLDocument: - doc, ok := arg1.(*dynamic.HTMLDocument) + case values.DHTMLDocument: + doc, ok := arg1.(values.DHTMLDocument) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -50,8 +50,8 @@ func Select(_ context.Context, args ...core.Value) (core.Value, error) { } return doc.SelectBySelector(arg2.(values.String), arg3.(*values.Array)) - case *dynamic.HTMLElement: - el, ok := arg1.(*dynamic.HTMLElement) + case values.DHTMLNode: + el, ok := arg1.(values.DHTMLNode) if !ok { return values.False, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/wait_class.go b/pkg/stdlib/html/wait_class.go index b531310c..8ff829b6 100644 --- a/pkg/stdlib/html/wait_class.go +++ b/pkg/stdlib/html/wait_class.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -42,7 +41,7 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) { // lets figure out what is passed as 1st argument switch args[0].(type) { - case *dynamic.HTMLDocument: + case values.DHTMLDocument: // revalidate args with more accurate amount err := core.ValidateArgs(args, 3, 4) @@ -57,7 +56,7 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) @@ -77,8 +76,8 @@ func WaitClass(_ context.Context, args ...core.Value) (core.Value, error) { } return values.None, doc.WaitForClass(selector, class, timeout) - case *dynamic.HTMLElement: - el, ok := args[0].(*dynamic.HTMLElement) + case values.DHTMLNode: + el, ok := args[0].(values.DHTMLNode) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/wait_class_all.go b/pkg/stdlib/html/wait_class_all.go index be1f60ae..8b86edb3 100644 --- a/pkg/stdlib/html/wait_class_all.go +++ b/pkg/stdlib/html/wait_class_all.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -42,7 +41,7 @@ func WaitClassAll(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/wait_element.go b/pkg/stdlib/html/wait_element.go index 27270d71..e84a11ae 100644 --- a/pkg/stdlib/html/wait_element.go +++ b/pkg/stdlib/html/wait_element.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -40,7 +39,7 @@ func WaitElement(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := arg.(*dynamic.HTMLDocument) + doc, ok := arg.(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic) diff --git a/pkg/stdlib/html/wait_navigation.go b/pkg/stdlib/html/wait_navigation.go index 30f6e99a..55389a7b 100644 --- a/pkg/stdlib/html/wait_navigation.go +++ b/pkg/stdlib/html/wait_navigation.go @@ -3,7 +3,6 @@ package html import ( "context" - "github.com/MontFerret/ferret/pkg/html/dynamic" "github.com/MontFerret/ferret/pkg/runtime/core" "github.com/MontFerret/ferret/pkg/runtime/values" ) @@ -25,7 +24,7 @@ func WaitNavigation(_ context.Context, args ...core.Value) (core.Value, error) { return values.None, err } - doc, ok := args[0].(*dynamic.HTMLDocument) + doc, ok := args[0].(values.DHTMLDocument) if !ok { return values.None, core.Errors(core.ErrInvalidType, ErrNotDynamic)