Repository: magic-test/magic-test-laravel Branch: master Commit: a2c2452c413c Files: 86 Total size: 182.0 KB Directory structure: gitextract_46m2sh82/ ├── .editorconfig ├── .gitattributes ├── .github/ │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ └── config.yml │ ├── SECURITY.md │ └── workflows/ │ ├── php-cs-fixer.yml │ └── run-tests.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── .phpcs ├── .phpunit.cache/ │ └── test-results ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── dist/ │ ├── magic_test.js │ └── magic_test.js.LICENSE.txt ├── js/ │ ├── AttributeParser.js │ ├── Context.js │ ├── Events/ │ │ ├── Click.js │ │ ├── Key.js │ │ └── Keypress.js │ ├── Finders.js │ ├── Helpers.js │ ├── Mutation.js │ └── magic_test.js ├── mix-manifest.json ├── package.json ├── phpunit.xml.dist ├── psalm.xml.dist ├── src/ │ ├── Commands/ │ │ └── MagicTestCommand.php │ ├── Controllers/ │ │ └── MagicTestController.php │ ├── Element/ │ │ └── Attribute.php │ ├── Exceptions/ │ │ └── InvalidFileException.php │ ├── FileEditor.php │ ├── Grammar/ │ │ ├── Click.php │ │ ├── Fill.php │ │ ├── Grammar.php │ │ ├── Pause.php │ │ └── See.php │ ├── MagicTest.php │ ├── MagicTestManager.php │ ├── MagicTestServiceProvider.php │ ├── Middleware/ │ │ ├── MagicTestMiddleware.php │ │ └── NullMagicTestMiddleware.php │ ├── Parser/ │ │ ├── File.php │ │ ├── Printer/ │ │ │ └── PrettyPrinter.php │ │ └── Visitors/ │ │ ├── GrammarBuilderVisitor.php │ │ └── MagicRemoverVisitor.php │ ├── PendingOk.php │ ├── ShellCommands/ │ │ ├── Finish.php │ │ └── Ok.php │ ├── Support/ │ │ └── AttributeCollection.php │ └── Traits/ │ └── UsesMagicTest.php ├── tests/ │ ├── Element/ │ │ └── AttributeTest.php │ ├── FileEditorTest.php │ ├── Grammar/ │ │ ├── ClickTest.php │ │ ├── FillTest.php │ │ └── SeeTest.php │ ├── MagicTestManagerTest.php │ ├── Parser/ │ │ └── FileTest.php │ ├── Support/ │ │ └── AttributeCollectionTest.php │ ├── TestCase.php │ └── fixtures/ │ ├── Errors/ │ │ ├── MissingClosure.php │ │ ├── MissingMethod.php │ │ └── MissingMethodCall.php │ ├── Finished/ │ │ ├── input.php │ │ ├── output.php │ │ └── output_with_click.php │ ├── Livewire/ │ │ ├── input.php │ │ └── output.php │ ├── MissingActions/ │ │ ├── input.php │ │ └── output.php │ ├── NeedsEscaping/ │ │ ├── input.php │ │ └── output.php │ ├── Regular/ │ │ ├── input.php │ │ └── output.php │ ├── WithActions/ │ │ ├── input.php │ │ └── output.php │ ├── WithActionsAndInlineCode/ │ │ ├── input.php │ │ ├── newFile.php │ │ └── output.php │ └── WithActionsAndTwoClosures/ │ ├── input.php │ └── output.php └── webpack.mix.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ root = true [*] charset = utf-8 indent_size = 4 indent_style = space end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true [*.md] trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 ================================================ FILE: .gitattributes ================================================ # Path-based git attributes # https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html # Ignore all test and documentation with "export-ignore". /.github export-ignore /.gitattributes export-ignore /.gitignore export-ignore /phpunit.xml.dist export-ignore /tests export-ignore /.editorconfig export-ignore /.php_cs.dist export-ignore /psalm.xml export-ignore /psalm.xml.dist export-ignore *.php text eol=lf ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing Contributions are **welcome** and will be fully **credited**. Please read and understand the contribution guide before creating an issue or pull request. ## Etiquette This project is open source, and as such, the maintainers give their free time to build and maintain the source code held within. They make the code freely available in the hope that it will be of use to other developers. It would be extremely unfair for them to suffer abuse or anger for their hard work. Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the world that developers are civilized and selfless people. It's the duty of the maintainer to ensure that all submissions to the project are of sufficient quality to benefit the project. Many developers have different skillsets, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. ## Viability When requesting or submitting new features, first consider whether it might be useful to others. Open source projects are used by many developers, who may have entirely different needs to your own. Think about whether or not your feature is likely to be used by other users of the project. ## Procedure Before filing an issue: - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. - Check to make sure your feature suggestion isn't already present within the project. - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. - Check the pull requests tab to ensure that the feature isn't already in progress. Before submitting a pull request: - Check the codebase to ensure that your feature doesn't already exist. - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. ## Requirements If the project maintainer has any additional requirements, you will find them listed here. - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). - **Add tests!** - Your patch won't be accepted if it doesn't have tests. - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. **Happy coding**! ================================================ FILE: .github/FUNDING.yml ================================================ github: mateusjatenee ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Ask a question url: https://github.com/magic-test/magic-test-laravel/discussions/new?category=q-a about: Ask the community for help - name: Request a feature url: https://github.com/magic-test/magic-test-laravel/discussions/new?category=ideas about: Share ideas for new features - name: Report a bug url: https://github.com/magic-test/magic-test-laravel/issues/new about: Report a reproducable bug ================================================ FILE: .github/SECURITY.md ================================================ # Security Policy If you discover any security related issues, please email mateus.jatene@gmail.com instead of using the issue tracker. ================================================ FILE: .github/workflows/php-cs-fixer.yml ================================================ name: Check & fix styling on: [push] jobs: php-cs-fixer: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v2 with: ref: ${{ github.head_ref }} - name: Run PHP CS Fixer uses: docker://oskarstark/php-cs-fixer-ga with: args: --allow-risky=yes - name: Commit changes uses: stefanzweifel/git-auto-commit-action@v4 with: commit_message: Fix styling ================================================ FILE: .github/workflows/run-tests.yml ================================================ name: run-tests on: [push, pull_request] jobs: test: runs-on: ${{ matrix.os }} strategy: fail-fast: true matrix: os: [ubuntu-latest, windows-latest] php: [8.1] laravel: [10.*] testbench: [8.*] stability: [prefer-lowest, prefer-stable] name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} steps: - name: Checkout code uses: actions/checkout@v2 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo coverage: none - name: Setup problem matchers run: | echo "::add-matcher::${{ runner.tool_cache }}/php.json" echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Install dependencies run: | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests run: vendor/bin/phpunit ================================================ FILE: .gitignore ================================================ .idea .php_cs .php_cs.cache .phpunit.result.cache .php-cs-fixer.cache build composer.lock coverage docs phpunit.xml psalm.xml vendor node_modules ================================================ FILE: .php-cs-fixer.dist.php ================================================ notPath('bootstrap/*') ->notPath('storage/*') ->notPath('resources/view/mail/*') ->in([ __DIR__ . '/src', __DIR__ . '/tests', ]) ->name('*.php') ->notName('*.blade.php') ->ignoreDotFiles(true) ->ignoreVCS(true); return (new PhpCsFixer\Config()) ->setRules([ '@PSR2' => true, 'array_syntax' => ['syntax' => 'short'], 'ordered_imports' => ['sort_algorithm' => 'alpha'], 'no_unused_imports' => true, 'not_operator_with_successor_space' => true, 'trailing_comma_in_multiline' => [ 'elements' => ['arrays'] ], 'phpdoc_scalar' => true, 'unary_operator_spaces' => true, 'binary_operator_spaces' => true, 'blank_line_before_statement' => [ 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], ], 'phpdoc_single_line_var_spacing' => true, 'phpdoc_var_without_name' => true, 'class_attributes_separation' => [ 'elements' => [ 'method' => 'one', ], ], 'method_argument_space' => [ 'on_multiline' => 'ensure_fully_multiline', 'keep_multiple_spaces_after_comma' => true, ], 'single_trait_insert_per_statement' => true, ]) ->setFinder($finder); ================================================ FILE: .phpcs ================================================ notPath('bootstrap/*') ->notPath('storage/*') ->notPath('resources/view/mail/*') ->in([ __DIR__ . '/src', __DIR__ . '/tests', ]) ->name('*.php') ->notName('*.blade.php') ->ignoreDotFiles(true) ->ignoreVCS(true); return PhpCsFixer\Config::create() ->setRules([ '@PSR2' => true, 'array_syntax' => ['syntax' => 'short'], 'ordered_imports' => ['sortAlgorithm' => 'alpha'], 'no_unused_imports' => true, 'not_operator_with_successor_space' => true, 'trailing_comma_in_multiline_array' => true, 'phpdoc_scalar' => true, 'unary_operator_spaces' => true, 'binary_operator_spaces' => true, 'blank_line_before_statement' => [ 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], ], 'phpdoc_single_line_var_spacing' => true, 'phpdoc_var_without_name' => true, 'class_attributes_separation' => [ 'elements' => [ 'method', ], ], 'method_argument_space' => [ 'on_multiline' => 'ensure_fully_multiline', 'keep_multiple_spaces_after_comma' => true, ], 'single_trait_insert_per_statement' => true, ]) ->setFinder($finder); ================================================ FILE: .phpunit.cache/test-results ================================================ {"version":1,"defects":[],"times":{"MagicTest\\MagicTest\\Tests\\Element\\AttributeTest::it_parses_a_livewire_name_field":0.006,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_replaces_the_method_content_when_it_does_not_have_actions":0.001,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_parses_a_file_that_uses_the_magic_macro":0.016,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_adds_fills_to_a_livewire_test":0.001,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_finishes_a_test_using_the_macro":0.001,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_adds_methods_to_a_file_using_inline_code":0.001,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_adds_content_to_a_file_with_two_closures":0.001,"MagicTest\\MagicTest\\Tests\\FileEditorTest::it_properly_escapes_a_string":0.001,"MagicTest\\MagicTest\\Tests\\Grammar\\ClickTest::it_properly_builds_a_select":0,"MagicTest\\MagicTest\\Tests\\Grammar\\ClickTest::it_properly_builds_a_radio":0.004,"MagicTest\\MagicTest\\Tests\\Grammar\\FillTest::it_properly_builds_an_action":0,"MagicTest\\MagicTest\\Tests\\Grammar\\FillTest::it_properly_adds_a_pause_to_a_livewire_input":0,"MagicTest\\MagicTest\\Tests\\Grammar\\FillTest::it_uses_the_livewire_selector_when_name_is_not_unique":0,"MagicTest\\MagicTest\\Tests\\Grammar\\FillTest::it_gives_priority_to_the_name_attribute":0,"MagicTest\\MagicTest\\Tests\\Grammar\\SeeTest::it_properly_builds_a_see_grammar":0,"MagicTest\\MagicTest\\Tests\\MagicTestManagerTest::it_replaces_the_content_of_a_file_with_actions":0.001,"MagicTest\\MagicTest\\Tests\\MagicTestManagerTest::it_replaces_the_content_of_a_file_without_actions":0.001,"MagicTest\\MagicTest\\Tests\\Parser\\FileTest::it_validates_a_class_missing_a_method":0.001,"MagicTest\\MagicTest\\Tests\\Parser\\FileTest::it_validates_a_class_missing_the_method_Call":0.001,"MagicTest\\MagicTest\\Tests\\Parser\\FileTest::it_validates_a_class_missing_the_closure":0.001,"MagicTest\\MagicTest\\Tests\\Support\\AttributeCollectionTest::it_reorders_attributes_including_a_name":0,"MagicTest\\MagicTest\\Tests\\Support\\AttributeCollectionTest::it_reorders_items_and_gives_preference_to_dusk":0}} ================================================ FILE: CHANGELOG.md ================================================ # Changelog All notable changes to `magic-test-laravel` will be documented in this file. ## 1.0.0 - 202X-XX-XX - initial release ================================================ FILE: LICENSE.md ================================================ The MIT License (MIT) Copyright (c) mateusjatenee Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Magic Test for Laravel [![Latest Version on Packagist](https://img.shields.io/packagist/v/magic-test/magic-test-laravel.svg?style=flat-square)](https://packagist.org/packages/magic-test/magic-test-laravel) [![GitHub Tests Action Status](https://img.shields.io/github/workflow/status/magic-test/magic-test-laravel/run-tests?label=tests)](https://github.com/magic-test/magic-test-laravel/actions?query=workflow%3ATests+branch%3Amaster) [![GitHub Code Style Action Status](https://img.shields.io/github/workflow/status/magic-test/magic-test-laravel/Check%20&%20fix%20styling?label=code%20style)](https://github.com/magic-test/magic-test-laravel/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amaster) [![Total Downloads](https://img.shields.io/packagist/dt/magic-test/magic-test-laravel.svg?style=flat-square)](https://packagist.org/packages/magic-test/magic-test-laravel) Magic Test allows you to write browser tests by simply clicking around on the application being tested, all without the slowness of constantly restarting the testing environment. It inverts the test-writing experience and avoids all the back and forth between tests, your terminal and your template files. [See it in action here.](https://twitter.com/mateusjatenee/status/1368905554790334464) The easiest way to explain Magic Test is through a video. [Check it out here](https://twitter.com/mateusjatenee/status/1368905554790334464). Magic Test was originally created by [Andrew Culver](http://twitter.com/andrewculver) and [Adam Pallozi](https://twitter.com/adampallozzi) for Ruby on Rails. Laravel Magic Test was created by [Mateus Guimarães](https://twitter.com/mateusjatenee). > Magic Test is still in early development, and that includes the documentation. Any questions you have that aren't already address in the documentation should be opened as issues so they can be appropriately addressed in the documentation. > :warning: **If you are using Windows/Laragon**: This package won't work with Windows/Laragon, since this doesn't support TTY. This package DOES work with WSL. ## Installation You can install the package via composer: ```bash composer require magic-test/magic-test-laravel --dev ``` ## Usage On your Laravel Dusk tests, simply add `magic()` at the end of your method chain. For example: ```php public function testBasicExample() { $this->browse(function (Browser $browser) { $browser->visit('/') ->magic(); }); } ``` To run Magic Test, you must simply run the command `php artisan magic`. Behind the scenes, it is the same as running `php artisan dusk`, but it will maintain the browser window open. This will leave you with two or three windows: - The browser - An interactive Shell - Your text editor if you had it open For the Magic Experience™️, we suggest you organize the three windows to fit your screen. That way, you can see tests being generated in real-time. ## Recording Actions Once the browser is open, Magic Test will already be capturing all of your actions. You can click around, fill inputs, checkboxes, selects and radios just like you would do manually testing an application. ## Generating Assertions Additionally, you can generate text assertions by selecting a given text and then pressing ControlShift + A. You'll see a dialog box confirming the assertion has been recorded. ## Saving the new actions to the test file To save the actions that were recorded, simply go to the Shell and type `ok`. You are free to close it and come back to your Magic Sessiona any time, or just keep recording more actions. If you're satisfied with your test, you can type `finish` on the Shell and it'll remove the `magic()` call from your test, leaving you with a clean, working test. See how it works [on this video](https://twitter.com/mateusjatenee/status/1368905554790334464) Magic Test is still in it's early days, so you might find that the output is not exactly what you wanted. In that case, [feel free to submit an issue](https://github.com/magic-test/magic-test-laravel/issues/new) and we'll try to improve it ASAP. ## Known issues Magic Test does not work well with Inertia.js assertions. If you're using Inertia in an integration test, please disable Magic Test by add the following code to your `setUp` method: ```php {var e={755:function(e,t){var n;!function(t,n){"use strict";"object"==typeof e.exports?e.exports=t.document?n(t,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return n(e)}:n(t)}("undefined"!=typeof window?window:this,(function(r,i){"use strict";var o=[],a=Object.getPrototypeOf,s=o.slice,u=o.flat?function(e){return o.flat.call(e)}:function(e){return o.concat.apply([],e)},l=o.push,c=o.indexOf,f={},p=f.toString,d=f.hasOwnProperty,h=d.toString,g=h.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},x=r.document,b={type:!0,src:!0,nonce:!0,noModule:!0};function w(e,t,n){var r,i,o=(n=n||x).createElement("script");if(o.text=e,t)for(r in b)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function T(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?f[p.call(e)]||"object":typeof e}var C="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function E(e){var t=!!e&&"length"in e&&e.length,n=T(e);return!m(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}S.fn=S.prototype={jquery:C,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(e){return this.pushStack(S.map(this,(function(t,n){return e.call(t,n,t)})))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,(function(e,t){return(t+1)%2})))},odd:function(){return this.pushStack(S.grep(this,(function(e,t){return t%2})))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|[\\x20\\t\\r\\n\\f])[\\x20\\t\\r\\n\\f]*"),z=new RegExp(M+"|>"),X=new RegExp(F),J=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\([\\x20\\t\\r\\n\\f]*(even|odd|(([+-]|)(\\d*)n|)[\\x20\\t\\r\\n\\f]*(?:([+-]|)[\\x20\\t\\r\\n\\f]*(\\d+)|))[\\x20\\t\\r\\n\\f]*\\)|)","i"),bool:new RegExp("^(?:"+P+")$","i"),needsContext:new RegExp("^[\\x20\\t\\r\\n\\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\([\\x20\\t\\r\\n\\f]*((?:-\\d)?\\d*)[\\x20\\t\\r\\n\\f]*\\)|)(?=[^-]|$)","i")},Q=/HTML$/i,G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}[\\x20\\t\\r\\n\\f]?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"�":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){p()},ae=be((function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()}),{dir:"parentNode",next:"legend"});try{O.apply(j=H.call(w.childNodes),w.childNodes),j[w.childNodes.length].nodeType}catch(e){O={apply:j.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}function se(e,t,r,i){var o,s,l,c,f,h,m,y=t&&t.ownerDocument,w=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==w&&9!==w&&11!==w)return r;if(!i&&(p(t),t=t||d,g)){if(11!==w&&(f=Z.exec(e)))if(o=f[1]){if(9===w){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(y&&(l=y.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return O.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!k[e+" "]&&(!v||!v.test(e))&&(1!==w||"object"!==t.nodeName.toLowerCase())){if(m=e,y=t,1===w&&(z.test(e)||U.test(e))){for((y=ee.test(e)&&me(t.parentNode)||t)===t&&n.scope||((c=t.getAttribute("id"))?c=c.replace(re,ie):t.setAttribute("id",c=b)),s=(h=a(e)).length;s--;)h[s]=(c?"#"+c:":scope")+" "+xe(h[s]);m=h.join(",")}try{return O.apply(r,y.querySelectorAll(m)),r}catch(t){k(e,!0)}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace($,"$1"),t,r,i)}function ue(){var e=[];return function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}}function le(e){return e[b]=!0,e}function ce(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){for(var n=e.split("|"),i=n.length;i--;)r.attrHandle[n[i]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function de(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function he(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ge(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ae(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function ve(e){return le((function(t){return t=+t,le((function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))}))}))}function me(e){return e&&void 0!==e.getElementsByTagName&&e}for(t in n=se.support={},o=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Q.test(t||n&&n.nodeName||"HTML")},p=se.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!=d&&9===a.nodeType&&a.documentElement?(h=(d=a).documentElement,g=!o(d),w!=d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",oe,!1):i.attachEvent&&i.attachEvent("onunload",oe)),n.scope=ce((function(e){return h.appendChild(e).appendChild(d.createElement("div")),void 0!==e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length})),n.attributes=ce((function(e){return e.className="i",!e.getAttribute("className")})),n.getElementsByTagName=ce((function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length})),n.getElementsByClassName=K.test(d.getElementsByClassName),n.getById=ce((function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length})),n.getById?(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(te,ne);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if(void 0!==t.getElementById&&g){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];for(i=t.getElementsByName(e),r=0;o=i[r++];)if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):n.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=n.getElementsByClassName&&function(e,t){if(void 0!==t.getElementsByClassName&&g)return t.getElementsByClassName(e)},m=[],v=[],(n.qsa=K.test(d.querySelectorAll))&&(ce((function(e){var t;h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\[[\\x20\\t\\r\\n\\f]*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||v.push("~="),(t=d.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\[[\\x20\\t\\r\\n\\f]*name[\\x20\\t\\r\\n\\f]*=[\\x20\\t\\r\\n\\f]*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")})),ce((function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name[\\x20\\t\\r\\n\\f]*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")}))),(n.matchesSelector=K.test(y=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ce((function(e){n.disconnectedMatch=y.call(e,"*"),y.call(e,"[s!='']:x"),m.push("!=",F)})),v=v.length&&new RegExp(v.join("|")),m=m.length&&new RegExp(m.join("|")),t=K.test(h.compareDocumentPosition),x=t||K.test(h.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)for(;t=t.parentNode;)if(t===e)return!0;return!1},A=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e==d||e.ownerDocument==w&&x(w,e)?-1:t==d||t.ownerDocument==w&&x(w,t)?1:c?I(c,e)-I(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==d?-1:t==d?1:i?-1:o?1:c?I(c,e)-I(c,t):0;if(i===o)return pe(e,t);for(n=e;n=n.parentNode;)a.unshift(n);for(n=t;n=n.parentNode;)s.unshift(n);for(;a[r]===s[r];)r++;return r?pe(a[r],s[r]):a[r]==w?-1:s[r]==w?1:0},d):d},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(p(e),n.matchesSelector&&g&&!k[t+" "]&&(!m||!m.test(t))&&(!v||!v.test(t)))try{var r=y.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){k(t,!0)}return se(t,d,null,[e]).length>0},se.contains=function(e,t){return(e.ownerDocument||e)!=d&&p(e),x(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&D.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(A),f){for(;t=e[o++];)t===e[o]&&(i=r.push(o));for(;i--;)e.splice(r[i],1)}return c=null,e},i=se.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r++];)n+=i(t);return n},r=se.selectors={cacheLength:50,createPseudo:le,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=S[e+" "];return t||(t=new RegExp("(^|[\\x20\\t\\r\\n\\f])"+e+"("+M+"|$)"))&&S(e,(function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")}))},ATTR:function(e,t,n){return function(r){var i=se.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace(B," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",v=t.parentNode,m=s&&t.nodeName.toLowerCase(),y=!u&&!s,x=!1;if(v){if(o){for(;g;){for(p=t;p=p[g];)if(s?p.nodeName.toLowerCase()===m:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?v.firstChild:v.lastChild],a&&y){for(x=(d=(l=(c=(f=(p=v)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&v.childNodes[d];p=++d&&p&&p[g]||(x=d=0)||h.pop();)if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(y&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)for(;(p=++d&&p&&p[g]||(x=d=0)||h.pop())&&((s?p.nodeName.toLowerCase()!==m:1!==p.nodeType)||!++x||(y&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p!==t)););return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?le((function(e,n){for(var r,o=i(e,t),a=o.length;a--;)e[r=I(e,o[a])]=!(n[r]=o[a])})):function(e){return i(e,0,n)}):i}},pseudos:{not:le((function(e){var t=[],n=[],r=s(e.replace($,"$1"));return r[b]?le((function(e,t,n,i){for(var o,a=r(e,null,i,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))})):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}})),has:le((function(e){return function(t){return se(e,t).length>0}})),contains:le((function(e){return e=e.replace(te,ne),function(t){return(t.textContent||i(t)).indexOf(e)>-1}})),lang:le((function(e){return J.test(e||"")||se.error("unsupported lang: "+e),e=e.replace(te,ne).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}})),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve((function(){return[0]})),last:ve((function(e,t){return[t-1]})),eq:ve((function(e,t,n){return[n<0?n+t:n]})),even:ve((function(e,t){for(var n=0;nt?t:n;--r>=0;)e.push(r);return e})),gt:ve((function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s-1&&(o[l]=!(a[l]=f))}}else m=Te(m===a?m.splice(h,m.length):m),i?i(null,a,m,u):O.apply(a,m)}))}function Se(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=be((function(e){return e===t}),s,!0),f=be((function(e){return I(t,e)>-1}),s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&we(p),u>1&&xe(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace($,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,v,m=0,y="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),S=T+=null==w?1:Math.random()||.1,E=C.length;for(c&&(l=a==d||a||c);y!==E&&null!=(f=C[y]);y++){if(i&&f){for(h=0,a||f.ownerDocument==d||(p(f),s=!g);v=e[h++];)if(v(f,a||d,s)){u.push(f);break}c&&(T=S)}n&&((f=!v&&f)&&m--,o&&x.push(f))}if(m+=y,n&&y!==m){for(h=0;v=t[h++];)v(x,b,a,s);if(o){if(m>0)for(;y--;)x[y]||b[y]||(b[y]=L.call(u));b=Te(b)}O.apply(u,b),c&&!o&&b.length>0&&m+t.length>1&&se.uniqueSort(u)}return c&&(T=S,l=w),x};return n?le(o):o}(o,i)),s.selector=e}return s},u=se.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(te,ne),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}for(o=V.needsContext.test(e)?0:u.length;o--&&(l=u[o],!r.relative[c=l.type]);)if((f=r.find[c])&&(i=f(l.matches[0].replace(te,ne),ee.test(u[0].type)&&me(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&xe(u)))return O.apply(n,i),n;break}}return(p||s(e,d))(i,t,!g,n,!t||ee.test(e)&&me(t.parentNode)||t),n},n.sortStable=b.split("").sort(A).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ce((function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))})),ce((function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")}))||fe("type|href|height|width",(function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)})),n.attributes&&ce((function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")}))||fe("value",(function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue})),ce((function(e){return null==e.getAttribute("disabled")}))||fe(P,(function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null})),se}(r);S.find=N,S.expr=N.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=N.uniqueSort,S.text=N.getText,S.isXMLDoc=N.isXML,S.contains=N.contains,S.escapeSelector=N.escape;var k=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},A=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=S.expr.match.needsContext;function j(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var L=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function q(e,t,n){return m(t)?S.grep(e,(function(e,r){return!!t.call(e,r,e)!==n})):t.nodeType?S.grep(e,(function(e){return e===t!==n})):"string"!=typeof t?S.grep(e,(function(e){return c.call(t,e)>-1!==n})):S.filter(t,e,n)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,(function(e){return 1===e.nodeType})))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter((function(){for(t=0;t1?S.uniqueSort(n):n},filter:function(e){return this.pushStack(q(this,e||[],!1))},not:function(e){return this.pushStack(q(this,e||[],!0))},is:function(e){return!!q(this,"string"==typeof e&&D.test(e)?S(e):e||[],!1).length}});var O,H=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||O,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:H.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:x,!0)),L.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=x.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,O=S(x);var I=/^(?:parents|prev(?:Until|All))/,P={children:!0,contents:!0,next:!0,prev:!0};function M(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter((function(){for(var e=0;e-1:1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?c.call(S(e),this[0]):c.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return M(e,"nextSibling")},prev:function(e){return M(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return A((e.parentNode||{}).firstChild,e)},children:function(e){return A(e.firstChild)},contents:function(e){return null!=e.contentDocument&&a(e.contentDocument)?e.contentDocument:(j(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},(function(e,t){S.fn[e]=function(n,r){var i=S.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=S.filter(r,i)),this.length>1&&(P[e]||S.uniqueSort(i),I.test(e)&&i.reverse()),this.pushStack(i)}}));var R=/[^\x20\t\r\n\f]+/g;function W(e){return e}function F(e){throw e}function B(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return S.each(e.match(R)||[],(function(e,n){t[n]=!0})),t}(e):S.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1)for(n=a.shift();++s-1;)o.splice(n,1),n<=s&&s--})),this},has:function(e){return e?S.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l},S.extend({Deferred:function(e){var t=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],n="pending",i={state:function(){return n},always:function(){return o.done(arguments).fail(arguments),this},catch:function(e){return i.then(null,e)},pipe:function(){var e=arguments;return S.Deferred((function(n){S.each(t,(function(t,r){var i=m(e[r[4]])&&e[r[4]];o[r[1]]((function(){var e=i&&i.apply(this,arguments);e&&m(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[r[0]+"With"](this,i?[e]:arguments)}))})),e=null})).promise()},then:function(e,n,i){var o=0;function a(e,t,n,i){return function(){var s=this,u=arguments,l=function(){var r,l;if(!(e=o&&(n!==F&&(s=void 0,u=[r]),t.rejectWith(s,u))}};e?c():(S.Deferred.getStackHook&&(c.stackTrace=S.Deferred.getStackHook()),r.setTimeout(c))}}return S.Deferred((function(r){t[0][3].add(a(0,r,m(i)?i:W,r.notifyWith)),t[1][3].add(a(0,r,m(e)?e:W)),t[2][3].add(a(0,r,m(n)?n:F))})).promise()},promise:function(e){return null!=e?S.extend(e,i):i}},o={};return S.each(t,(function(e,r){var a=r[2],s=r[5];i[r[1]]=a.add,s&&a.add((function(){n=s}),t[3-e][2].disable,t[3-e][3].disable,t[0][2].lock,t[0][3].lock),a.add(r[3].fire),o[r[0]]=function(){return o[r[0]+"With"](this===o?void 0:this,arguments),this},o[r[0]+"With"]=a.fireWith})),i.promise(o),e&&e.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=s.call(arguments),o=S.Deferred(),a=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?s.call(arguments):n,--t||o.resolveWith(r,i)}};if(t<=1&&(B(e,o.done(a(n)).resolve,o.reject,!t),"pending"===o.state()||m(i[n]&&i[n].then)))return o.then();for(;n--;)B(i[n],a(n),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){r.console&&r.console.warn&&e&&$.test(e.name)&&r.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){r.setTimeout((function(){throw e}))};var _=S.Deferred();function U(){x.removeEventListener("DOMContentLoaded",U),r.removeEventListener("load",U),S.ready()}S.fn.ready=function(e){return _.then(e).catch((function(e){S.readyException(e)})),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0,!0!==e&&--S.readyWait>0||_.resolveWith(x,[S]))}}),S.ready.then=_.then,"complete"===x.readyState||"loading"!==x.readyState&&!x.documentElement.doScroll?r.setTimeout(S.ready):(x.addEventListener("DOMContentLoaded",U),r.addEventListener("load",U));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===T(n))for(s in i=!0,n)z(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each((function(){Z.remove(this,e)}))}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=K.get(e,t),n&&(!r||Array.isArray(n)?r=K.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,(function(){S.dequeue(e,t)}),o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return K.get(e,n)||K.access(e,n,{empty:S.Callbacks("once memory").add((function(){K.remove(e,[t+"queue",n])}))})}}),S.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,ye=/^$|^module$|\/(?:java|ecma)script/i;he=x.createDocumentFragment().appendChild(x.createElement("div")),(ge=x.createElement("input")).setAttribute("type","radio"),ge.setAttribute("checked","checked"),ge.setAttribute("name","t"),he.appendChild(ge),v.checkClone=he.cloneNode(!0).cloneNode(!0).lastChild.checked,he.innerHTML="",v.noCloneChecked=!!he.cloneNode(!0).lastChild.defaultValue,he.innerHTML="",v.option=!!he.lastChild;var xe={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function be(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&j(e,t)?S.merge([e],n):n}function we(e,t){for(var n=0,r=e.length;n",""]);var Te=/<|&#?\w+;/;function Ce(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d-1)i&&i.push(o);else if(l=se(o),a=be(f.appendChild(o),"script"),l&&we(a),n)for(c=0;o=a[c++];)ye.test(o.type||"")&&n.push(o);return f}var Se=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function Ne(){return!1}function ke(e,t){return e===function(){try{return x.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Ne;else if(!i)return e;return 1===o&&(a=i,i=function(e){return S().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=S.guid++)),e.each((function(){S.event.add(this,t,i,r,n)}))}function De(e,t,n){n?(K.set(e,t,!1),S.event.add(e,t,{namespace:!1,handler:function(e){var r,i,o=K.get(this,t);if(1&e.isTrigger&&this[t]){if(o.length)(S.event.special[t]||{}).delegateType&&e.stopPropagation();else if(o=s.call(arguments),K.set(this,t,o),r=n(this,t),this[t](),o!==(i=K.get(this,t))||r?K.set(this,t,!1):i={},o!==i)return e.stopImmediatePropagation(),e.preventDefault(),i&&i.value}else o.length&&(K.set(this,t,{value:S.event.trigger(S.extend(o[0],S.Event.prototype),o.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===K.get(e,t)&&S.event.add(e,t,Ee)}S.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=K.get(e);if(G(e))for(n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(ae,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(t){return void 0!==S&&S.event.triggered!==t.type?S.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(R)||[""]).length;l--;)d=g=(s=Se.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=K.hasData(e)&&K.get(e);if(v&&(u=v.events)){for(l=(t=(t||"").match(R)||[""]).length;l--;)if(d=g=(s=Se.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){for(f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;o--;)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&K.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(K.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\s*$/g;function Oe(e,t){return j(e,"table")&&j(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Ie(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(K.hasData(e)&&(s=K.get(e).events))for(i in K.remove(t,"handle events"),s)for(n=0,r=s[i].length;n1&&"string"==typeof h&&!v.checkClone&&Le.test(h))return e.each((function(i){var o=e.eq(i);g&&(t[0]=h.call(this,i,o.html())),Re(o,t,n,r)}));if(p&&(o=(i=Ce(t,e[0].ownerDocument,!1,e,r)).firstChild,1===i.childNodes.length&&(i=o),o||r)){for(s=(a=S.map(be(i,"script"),He)).length;f0&&we(a,!u&&be(e,"script")),s},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[K.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[K.expando]=void 0}n[Z.expando]&&(n[Z.expando]=void 0)}}}),S.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return z(this,(function(e){return void 0===e?S.text(this):this.empty().each((function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)}))}),null,e,arguments.length)},append:function(){return Re(this,arguments,(function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)}))},prepend:function(){return Re(this,arguments,(function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}}))},before:function(){return Re(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this)}))},after:function(){return Re(this,arguments,(function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)}))},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(be(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map((function(){return S.clone(this,e,t)}))},html:function(e){return z(this,(function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!je.test(e)&&!xe[(me.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function nt(e,t,n){var r=Be(e),i=(!v.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=Ue(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Fe.test(a)){if(!n)return a;a="auto"}return(!v.boxSizingReliable()&&i||!v.reliableTrDimensions()&&j(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+tt(e,t,n||(i?"border":"content"),o,r,a)+"px"}function rt(e,t,n,r,i){return new rt.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ue(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=Q(t),u=Ye.test(t),l=e.style;if(u||(t=Qe(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ce(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),v.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=Q(t);return Ye.test(t)||(t=Qe(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ue(e,t,r)),"normal"===i&&t in Ze&&(i=Ze[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],(function(e,t){S.cssHooks[t]={get:function(e,n,r){if(n)return!Ge.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?nt(e,t,r):$e(e,Ke,(function(){return nt(e,t,r)}))},set:function(e,n,r){var i,o=Be(e),a=!v.scrollboxSize()&&"absolute"===o.position,s=(a||r)&&"border-box"===S.css(e,"boxSizing",!1,o),u=r?tt(e,t,r,s,o):0;return s&&a&&(u-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-tt(e,t,"border",!1,o)-.5)),u&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=S.css(e,t)),et(0,n,u)}}})),S.cssHooks.marginLeft=ze(v.reliableMarginLeft,(function(e,t){if(t)return(parseFloat(Ue(e,"marginLeft"))||e.getBoundingClientRect().left-$e(e,{marginLeft:0},(function(){return e.getBoundingClientRect().left})))+"px"})),S.each({margin:"",padding:"",border:"Width"},(function(e,t){S.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(S.cssHooks[e+t].set=et)})),S.fn.extend({css:function(e,t){return z(this,(function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Be(e),i=t.length;a1)}}),S.Tween=rt,rt.prototype={constructor:rt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=rt.propHooks[this.prop];return e&&e.get?e.get(this):rt.propHooks._default.get(this)},run:function(e){var t,n=rt.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rt.propHooks._default.set(this),this}},rt.prototype.init.prototype=rt.prototype,rt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[Qe(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}},rt.propHooks.scrollTop=rt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=rt.prototype.init,S.fx.step={};var it,ot,at=/^(?:toggle|show|hide)$/,st=/queueHooks$/;function ut(){ot&&(!1===x.hidden&&r.requestAnimationFrame?r.requestAnimationFrame(ut):r.setTimeout(ut,S.fx.interval),S.fx.tick())}function lt(){return r.setTimeout((function(){it=void 0})),it=Date.now()}function ct(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ft(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each((function(){S.removeAttr(this,e)}))}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return void 0===e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!v.radioValue&&"radio"===t&&j(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)for(;n=i[r++];)e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),(function(e,t){var n=ht[t]||S.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}}));var gt=/^(?:input|select|textarea|button)$/i,vt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(" ")}function yt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}S.fn.extend({prop:function(e,t){return z(this,S.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each((function(){delete this[S.propFix[e]||e]}))}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||vt.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),v.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],(function(){S.propFix[this.toLowerCase()]=this})),S.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(m(e))return this.each((function(t){S(this).addClass(e.call(this,t,yt(this)))}));if((t=xt(e)).length)for(;n=this[u++];)if(i=yt(n),r=1===n.nodeType&&" "+mt(i)+" "){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(m(e))return this.each((function(t){S(this).removeClass(e.call(this,t,yt(this)))}));if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)for(;n=this[u++];)if(i=yt(n),r=1===n.nodeType&&" "+mt(i)+" "){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):m(e)?this.each((function(n){S(this).toggleClass(e.call(this,n,yt(this),t),t)})):this.each((function(){var t,i,o,a;if(r)for(i=0,o=S(this),a=xt(e);t=a[i++];)o.hasClass(t)?o.removeClass(t):o.addClass(t);else void 0!==e&&"boolean"!==n||((t=yt(this))&&K.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":K.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+mt(yt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;S.fn.extend({val:function(e){var t,n,r,i=this[0];return arguments.length?(r=m(e),this.each((function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,S(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=S.map(i,(function(e){return null==e?"":e+""}))),(t=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))}))):i?(t=S.valHooks[i.type]||S.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:mt(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],(function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=S.inArray(S(e).val(),t)>-1}},v.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})})),v.focusin="onfocusin"in r;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,i){var o,a,s,u,l,c,f,p,h=[n||x],g=d.call(e,"type")?e.type:e,v=d.call(e,"namespace")?e.namespace.split("."):[];if(a=p=s=n=n||x,3!==n.nodeType&&8!==n.nodeType&&!wt.test(g+S.event.triggered)&&(g.indexOf(".")>-1&&(v=g.split("."),g=v.shift(),v.sort()),l=g.indexOf(":")<0&&"on"+g,(e=e[S.expando]?e:new S.Event(g,"object"==typeof e&&e)).isTrigger=i?2:3,e.namespace=v.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+v.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),f=S.event.special[g]||{},i||!f.trigger||!1!==f.trigger.apply(n,t))){if(!i&&!f.noBubble&&!y(n)){for(u=f.delegateType||g,wt.test(u+g)||(a=a.parentNode);a;a=a.parentNode)h.push(a),s=a;s===(n.ownerDocument||x)&&h.push(s.defaultView||s.parentWindow||r)}for(o=0;(a=h[o++])&&!e.isPropagationStopped();)p=a,e.type=o>1?u:f.bindType||g,(c=(K.get(a,"events")||Object.create(null))[e.type]&&K.get(a,"handle"))&&c.apply(a,t),(c=l&&a[l])&&c.apply&&G(a)&&(e.result=c.apply(a,t),!1===e.result&&e.preventDefault());return e.type=g,i||e.isDefaultPrevented()||f._default&&!1!==f._default.apply(h.pop(),t)||!G(n)||l&&m(n[g])&&!y(n)&&((s=n[l])&&(n[l]=null),S.event.triggered=g,e.isPropagationStopped()&&p.addEventListener(g,Tt),n[g](),e.isPropagationStopped()&&p.removeEventListener(g,Tt),S.event.triggered=void 0,s&&(n[l]=s)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each((function(){S.event.trigger(e,t,this)}))},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),v.focusin||S.each({focus:"focusin",blur:"focusout"},(function(e,t){var n=function(e){S.event.simulate(t,e.target,S.event.fix(e))};S.event.special[t]={setup:function(){var r=this.ownerDocument||this.document||this,i=K.access(r,t);i||r.addEventListener(e,n,!0),K.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this.document||this,i=K.access(r,t)-1;i?K.access(r,t,i):(r.removeEventListener(e,n,!0),K.remove(r,t))}}}));var Ct=r.location,St={guid:Date.now()},Et=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new r.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,(function(e){return e.textContent})).join("\n"):e)),t};var Nt=/\[\]$/,kt=/\r?\n/g,At=/^(?:submit|button|image|reset|file)$/i,Dt=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))S.each(t,(function(t,i){n||Nt.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)}));else if(n||"object"!==T(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,(function(){i(this.name,this.value)}));else for(n in e)jt(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map((function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this})).filter((function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&Dt.test(this.nodeName)&&!At.test(e)&&(this.checked||!ve.test(e))})).map((function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,(function(e){return{name:t.name,value:e.replace(kt,"\r\n")}})):{name:t.name,value:n.replace(kt,"\r\n")}})).get()}});var Lt=/%20/g,qt=/#.*$/,Ot=/([?&])_=[^&]*/,Ht=/^(.*?):[ \t]*([^\r\n]*)$/gm,It=/^(?:GET|HEAD)$/,Pt=/^\/\//,Mt={},Rt={},Wt="*/".concat("*"),Ft=x.createElement("a");function Bt(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(R)||[];if(m(n))for(;r=o[i++];)"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function $t(e,t,n,r){var i={},o=e===Rt;function a(s){var u;return i[s]=!0,S.each(e[s]||[],(function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)})),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function _t(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Ft.href=Ct.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Wt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_t(_t(e,S.ajaxSettings),t):_t(S.ajaxSettings,e)},ajaxPrefilter:Bt(Mt),ajaxTransport:Bt(Rt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var n,i,o,a,s,u,l,c,f,p,d=S.ajaxSetup({},t),h=d.context||d,g=d.context&&(h.nodeType||h.jquery)?S(h):S.event,v=S.Deferred(),m=S.Callbacks("once memory"),y=d.statusCode||{},b={},w={},T="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(l){if(!a)for(a={};t=Ht.exec(o);)a[t[1].toLowerCase()+" "]=(a[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=a[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return l?o:null},setRequestHeader:function(e,t){return null==l&&(e=w[e.toLowerCase()]=w[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==l&&(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(l)C.always(e[C.status]);else for(t in e)y[t]=[y[t],e[t]];return this},abort:function(e){var t=e||T;return n&&n.abort(t),E(0,t),this}};if(v.promise(C),d.url=((e||d.url||Ct.href)+"").replace(Pt,Ct.protocol+"//"),d.type=t.method||t.type||d.method||d.type,d.dataTypes=(d.dataType||"*").toLowerCase().match(R)||[""],null==d.crossDomain){u=x.createElement("a");try{u.href=d.url,u.href=u.href,d.crossDomain=Ft.protocol+"//"+Ft.host!=u.protocol+"//"+u.host}catch(e){d.crossDomain=!0}}if(d.data&&d.processData&&"string"!=typeof d.data&&(d.data=S.param(d.data,d.traditional)),$t(Mt,d,t,C),l)return C;for(f in(c=S.event&&d.global)&&0==S.active++&&S.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!It.test(d.type),i=d.url.replace(qt,""),d.hasContent?d.data&&d.processData&&0===(d.contentType||"").indexOf("application/x-www-form-urlencoded")&&(d.data=d.data.replace(Lt,"+")):(p=d.url.slice(i.length),d.data&&(d.processData||"string"==typeof d.data)&&(i+=(Et.test(i)?"&":"?")+d.data,delete d.data),!1===d.cache&&(i=i.replace(Ot,"$1"),p=(Et.test(i)?"&":"?")+"_="+St.guid+++p),d.url=i+p),d.ifModified&&(S.lastModified[i]&&C.setRequestHeader("If-Modified-Since",S.lastModified[i]),S.etag[i]&&C.setRequestHeader("If-None-Match",S.etag[i])),(d.data&&d.hasContent&&!1!==d.contentType||t.contentType)&&C.setRequestHeader("Content-Type",d.contentType),C.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Wt+"; q=0.01":""):d.accepts["*"]),d.headers)C.setRequestHeader(f,d.headers[f]);if(d.beforeSend&&(!1===d.beforeSend.call(h,C,d)||l))return C.abort();if(T="abort",m.add(d.complete),C.done(d.success),C.fail(d.error),n=$t(Rt,d,t,C)){if(C.readyState=1,c&&g.trigger("ajaxSend",[C,d]),l)return C;d.async&&d.timeout>0&&(s=r.setTimeout((function(){C.abort("timeout")}),d.timeout));try{l=!1,n.send(b,E)}catch(e){if(l)throw e;E(-1,e)}}else E(-1,"No Transport");function E(e,t,a,u){var f,p,x,b,w,T=t;l||(l=!0,s&&r.clearTimeout(s),n=void 0,o=u||"",C.readyState=e>0?4:0,f=e>=200&&e<300||304===e,a&&(b=function(e,t,n){for(var r,i,o,a,s=e.contents,u=e.dataTypes;"*"===u[0];)u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(d,C,a)),!f&&S.inArray("script",d.dataTypes)>-1&&S.inArray("json",d.dataTypes)<0&&(d.converters["text script"]=function(){}),b=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];for(o=c.shift();o;)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e.throws)t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(d,b,C,f),f?(d.ifModified&&((w=C.getResponseHeader("Last-Modified"))&&(S.lastModified[i]=w),(w=C.getResponseHeader("etag"))&&(S.etag[i]=w)),204===e||"HEAD"===d.type?T="nocontent":304===e?T="notmodified":(T=b.state,p=b.data,f=!(x=b.error))):(x=T,!e&&T||(T="error",e<0&&(e=0))),C.status=e,C.statusText=(t||T)+"",f?v.resolveWith(h,[p,T,C]):v.rejectWith(h,[C,T,x]),C.statusCode(y),y=void 0,c&&g.trigger(f?"ajaxSuccess":"ajaxError",[C,d,f?p:x]),m.fireWith(h,[C,T]),c&&(g.trigger("ajaxComplete",[C,d]),--S.active||S.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],(function(e,t){S[t]=function(e,n,r,i){return m(n)&&(i=i||r,r=n,n=void 0),S.ajax(S.extend({url:e,type:t,dataType:i,data:n,success:r},S.isPlainObject(e)&&e))}})),S.ajaxPrefilter((function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")})),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map((function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e})).append(this)),this},wrapInner:function(e){return m(e)?this.each((function(t){S(this).wrapInner(e.call(this,t))})):this.each((function(){var t=S(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)}))},wrap:function(e){var t=m(e);return this.each((function(n){S(this).wrapAll(t?e.call(this,n):e)}))},unwrap:function(e){return this.parent(e).not("body").each((function(){S(this).replaceWith(this.childNodes)})),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new r.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},zt=S.ajaxSettings.xhr();v.cors=!!zt&&"withCredentials"in zt,v.ajax=zt=!!zt,S.ajaxTransport((function(e){var t,n;if(v.cors||zt&&!e.crossDomain)return{send:function(i,o){var a,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(a in e.xhrFields)s[a]=e.xhrFields[a];for(a in e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest"),i)s.setRequestHeader(a,i[a]);t=function(e){return function(){t&&(t=n=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Ut[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=t(),n=s.onerror=s.ontimeout=t("error"),void 0!==s.onabort?s.onabort=n:s.onreadystatechange=function(){4===s.readyState&&r.setTimeout((function(){t&&n()}))},t=t("abort");try{s.send(e.hasContent&&e.data||null)}catch(e){if(t)throw e}},abort:function(){t&&t()}}})),S.ajaxPrefilter((function(e){e.crossDomain&&(e.contents.script=!1)})),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",(function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")})),S.ajaxTransport("script",(function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(r,i){t=S("'; return implode("\n", $html); } public static function disable(): void { app()->bind(MagicTestMiddleware::class, NullMagicTestMiddleware::class); } } ================================================ FILE: src/MagicTestManager.php ================================================ withArguments()->limit(10)->frames()); // this means it was called with the magic() macro if ($backtrace[3]->method === '__call') { $caller = $backtrace[6]; $testMethod = $caller->method; } else { $callerKey = $backtrace[1]->method === 'magic_test' ? 2 : 1; $caller = $backtrace[$callerKey]; $testMethod = $backtrace[$callerKey + 2]->method; } MagicTest::setBrowserInstance($browser); MagicTest::setTestMethod($testMethod); MagicTest::setOpenFile($caller->file); $browser->script('MagicTest.run()'); $shell = new Shell(new Configuration([ 'startupMessage' => "\n" . '*** Welcome to your 🧙 Magic Test session! ***' . "\n" . "\n* To make a assertion press Ctrl + Shift + A on your browser." . "\n* Type ok to magically write it to your test file." . "\n (make as many assertions as you wish)" . "\n* Type finish to finalize and save your test file." . "\n* Type exit to leave." . "\n" . "\n💡 Tip: Do not close your browser window before finalizing this session here.", ])); $shell->addCommands([ new Ok, new Finish, ]); $shell->run(); } public function runScripts(): string { $browser = MagicTest::$browser; $output = json_decode($browser->driver->executeScript('return MagicTest.getData()'), true); $grammar = collect($output)->map(fn ($command) => Grammar::for($command)); if (is_null($grammar) || $grammar->isEmpty()) { return "No actions were added to " . MagicTest::$file . '::' . MagicTest::$method; } $this->buildTest($grammar); $browser->script('MagicTest.clear()'); return '🧙 ' . $grammar->count() . ' new ' . Str::plural('action', $grammar->count()) . ($grammar->count() > 1 ? ' were' : ' was') . ' added to ' . MagicTest::$file . '::' . MagicTest::$method . ''; } public function finish(): string { $content = file_get_contents(MagicTest::$file); $method = MagicTest::$method; file_put_contents( MagicTest::$file, (new FileEditor)->finish($content, $method) ); return 'Your 🧙 Magic Test session has finished. See you later! 👋 '; } public function buildTest(Collection $grammar): void { $content = file_get_contents(MagicTest::$file); $method = MagicTest::$method; file_put_contents( MagicTest::$file, (new FileEditor)->process($content, $grammar, $method) ); } } ================================================ FILE: src/MagicTestServiceProvider.php ================================================ name('magic-test-laravel') ->hasCommand(MagicTestCommand::class); } public function boot() { parent::boot(); $this->app->singleton('magic-test-laravel', fn ($app) => new MagicTest); $this->app['router']->pushMiddlewareToGroup('web', MagicTestMiddleware::class); Browser::macro('magic', fn () => MagicTestManager::run($this)); Browser::macro('clickElement', function ($selector, $value) { foreach ($this->resolver->all($selector) as $element) { if (Str::contains($element->getText(), $value)) { $element->click(); return $this; } } throw new InvalidArgumentException( "Unable to locate element [${selector}] with content [{$value}]." ); }); Blade::directive('magicTestScripts', [MagicTest::class, 'scripts']); } } ================================================ FILE: src/Middleware/MagicTestMiddleware.php ================================================ environment(['local', 'testing', 'dusk'])) { return $next($request); } /** @var \Illuminate\Http\Response $response */ $response = $next($request); if (! $this->responseContainsClosingHtmlTag($response)) { return $response; } return tap($response)->setContent( $this->addMagicTestScriptsToResponseContent($response->getContent()) ); } protected function responseContainsClosingHtmlTag(Response $response): bool { return mb_strpos($response->getContent(), '') !== false; } /** * @param string $responseContent * @return string */ protected function addMagicTestScriptsToResponseContent(string $responseContent): string { $scripts = MagicTest::scripts(); return Str::replaceLast( '', "{$scripts} \n ", $responseContent ); } } ================================================ FILE: src/Middleware/NullMagicTestMiddleware.php ================================================ lexer = new \PhpParser\Lexer\Emulative([ 'usedAttributes' => [ 'comments', 'startLine', 'endLine', 'startTokenPos', 'endTokenPos', ], ]); $this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7, $this->lexer); $this->ast = (array) $this->parser->parse($content)[0]; $this->initialStatements = $this->ast['stmts']; $this->newStatements = $this->getNewStatements(); $this->closure = $this->getClosure($method); } public static function fromContent(string $content, string $method) { return new static($content, $method); } public function addMethods(Collection $grammar): string { $traverser = new NodeTraverser; $traverser->addVisitor(new ParentConnectingVisitor); $traverser->addVisitor(new GrammarBuilderVisitor($grammar)); $traverser->traverse($this->closure->stmts); return $this->print(); } public function finish(): string { $traverser = new NodeTraverser; $traverser->addVisitor(new ParentConnectingVisitor); $traverser->addVisitor(new MagicRemoverVisitor); $traverser->traverse($this->closure->stmts); return $this->print(); } protected function print(): string { return (new PrettyPrinter)->printFormatPreserving( $this->newStatements, $this->initialStatements, $this->lexer->getTokens() ); } /** * Clone the statements to leave the starting ones untouched so they can be diffed by the printer later. * * @return array */ protected function getNewStatements(): array { $traverser = new NodeTraverser; $traverser->addVisitor(new CloningVisitor); return $traverser->traverse($this->initialStatements); } protected function getClassMethod(string $method): ?ClassMethod { return (new NodeFinder)->findFirst( $this->newStatements, fn (Node $node) => $node instanceof ClassMethod && $node->name->__toString() === $method ); } /** * Finds the first valid method call inside a class method. * A valid method call is one that is both a MethodCall instance and * that also has a node that is a Identifier and ahs the name magic. * * @param \PhpParser\Node\Stmt\ClassMethod $classMethod * @return \PhpParser\Node\Expr\MethodCall|null */ protected function getMethodCall(ClassMethod $classMethod): ?MethodCall { return (new NodeFinder)->findFirst($classMethod->stmts, function (Node $node) { return $node instanceof MethodCall && (new NodeFinder)->find( $node->args, fn (Node $node) => $node instanceof Identifier && $node->name === 'magic' ); }); } /** * Get the closure object * * @param string $method * @throws \MagicTest\MagicTest\Exceptions\InvalidFileException * @return Closure */ protected function getClosure(string $method): ?Closure { $classMethod = $this->getClassMethod($method); throw_if(! $classMethod, new InvalidFileException("Could not find method {$method} on file.")); $methodCall = $this->getMethodCall($classMethod); throw_if(! $methodCall, new InvalidFileException("Could not find the browse call on file.")); $closure = (new NodeFinder)->findFirst($methodCall->args, fn (Node $node) => $node->value instanceof Closure); throw_if(! $closure, new InvalidFileException("Could not find the closure on file.")); return $closure->value; } } ================================================ FILE: src/Parser/Printer/PrettyPrinter.php ================================================ ' . $this->pObjectProperty($node->name) . '(' . $this->pMaybeMultiline($node->args) . ')', 1); return $this->pDereferenceLhs($node->var) . $this->nl . $call; } } ================================================ FILE: src/Parser/Visitors/GrammarBuilderVisitor.php ================================================ grammar = $grammar; } public function leaveNode(Node $node): void { if ($node instanceof MethodCall && $node->name->__toString() === 'magic') { $this->buildNodes($node); } } /** * Builds the necessary methods with their arguments, * properly adds pauses between them when needed * and then adds the necessary nodes. * * @param \PhpParser\Node $node * @return void */ public function buildNodes($node): void { $previousMethod = $this->getPreviousMethodInChain($node); $grammar = $this->grammar ->map(function ($grammar) { return [$grammar, $grammar->pause()]; })->flatten()->filter(); // if the last item of a grammar is a pause, it is unnecessary because // right now we are in the "magic" call node, so we remove it. // That happens unless the second to last grammar is a Livewire field. // In that case we have to add an extra pause regardless. $secondToLastGrammar = $grammar->count() > 1 ? $grammar[$grammar->count() - 2] : null; if ( $grammar->last() instanceof Pause && ! $secondToLastGrammar->isLivewire() ) { $grammar->pop(); } // If the previous method was a method // that needs a pause, we prepend it. if (in_array($previousMethod->name->__toString(), [ 'clickLink', 'press', ])) { $grammar->prepend(new Pause(500)); } // I'll be honest and say I don't entirely understand the folllowing block of code, // even though I wrote it. // I'm still a bit confused as to why there are nested method call objects inside each var // (so each method call's var is another method call) instead of them being siblings. foreach ($grammar as $gram) { $previousNode = clone $node; $node->var = new MethodCall( $previousNode->var, $gram->nameForParser(), $this->buildArguments($gram->arguments()) ); } } public function buildArguments(array $arguments): array { return array_map(fn ($argument) => new Arg($argument), $arguments); } public function getPreviousMethodInChain(Node $node): Expr { $parentExpression = $node->getAttribute('parent')->expr; // now we return the first var, which *should* be the previous method. return $parentExpression->var; } } ================================================ FILE: src/Parser/Visitors/MagicRemoverVisitor.php ================================================ name->__toString() === 'magic') { $previousMethod = $this->getPreviousMethodInChain($node); // We are mutating the currenet method (magic) to have the properties // of the previous method. That way we get rid of it. Is this the // correct way? No fucking clue. But it's working. I think. $node->name = $previousMethod->name; $node->var = $previousMethod->var; $node->args = $previousMethod->args; } } public function getPreviousMethodInChain(Node $node): Expr { $parentExpression = $node->getAttribute('parent')->expr; // now we return the first var, which *should* be the previous method. return $parentExpression->var; } } ================================================ FILE: src/PendingOk.php ================================================ runScripts(); } } ================================================ FILE: src/ShellCommands/Finish.php ================================================ setName('finish') ->setDefinition([]); } protected function execute(InputInterface $input, OutputInterface $output) { $actionOutput = (new MagicTestManager)->finish(); $output->write("{$actionOutput}", true); return 0; } } ================================================ FILE: src/ShellCommands/Ok.php ================================================ setName('ok') ->setDefinition([]); } protected function execute(InputInterface $input, OutputInterface $output) { $scriptOutput = (new MagicTestManager)->runScripts(); $output->write("{$scriptOutput}", true); return 0; } } ================================================ FILE: src/Support/AttributeCollection.php ================================================ where('name', $name)->isNotEmpty(); } public function getAttribute(string $name): string { return $this->where('name', $name)->first()->value; } /** * The "dusk" and "name" attributes should always be the priority. * * @return self */ public function reorderItems(): self { $newCollection = new static; foreach ($this->attributeOrder as $attribute) { if ($this->hasAttribute($attribute)) { $newCollection->push( $this->where('name', $attribute)->first() ); } } return $newCollection->merge( $this->whereNotIn('name', $this->attributeOrder) ); } } ================================================ FILE: src/Traits/UsesMagicTest.php ================================================ assertEquals('input[wire\\:model=name]', $attribute->buildSelector()); } } ================================================ FILE: tests/FileEditorTest.php ================================================ 'Log in']), new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); $processedText = (new FileEditor)->process($expectedInput, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_properly_parses_a_file_that_uses_the_magic_macro() { $expectedInput = file_get_contents(__DIR__ . '/fixtures/WithActions/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/WithActions/output.php'); $grammar = collect([ new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); $processedText = (new FileEditor)->process($expectedInput, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_properly_adds_fills_to_a_livewire_test() { $input = file_get_contents(__DIR__ . '/fixtures/Livewire/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/Livewire/output.php'); $grammar = collect([ new Fill([ ['name' => 'name', 'value' => 'name'], ['name' => 'wire:model', 'value' => 'name'], ], [], 'input', [ 'text' => 'Mateus', ]), new Fill([ ['name' => 'name', 'value' => 'email'], ['name' => 'wire:model', 'email'], ], [], 'input', [ 'text' => 'mateus@mateusguimaraes.com', ]), ]); $processedText = (new FileEditor)->process($input, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_finishes_a_test_using_the_macro() { $expectedInput = file_get_contents(__DIR__ . '/fixtures/Finished/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/Finished/output.php'); $processedText = (new FileEditor)->finish($expectedInput, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_properly_adds_methods_to_a_file_using_inline_code() { $expectedInput = file_get_contents(__DIR__ . '/fixtures/WithActionsAndInlineCode/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/WithActionsAndInlineCode/output.php'); $grammar = collect([ new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); $processedText = (new FileEditor)->process($expectedInput, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_properly_adds_content_to_a_file_with_two_closures() { $expectedInput = file_get_contents(__DIR__ . '/fixtures/WithActionsAndTwoClosures/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/WithActionsAndTwoClosures/output.php'); $grammar = collect([ new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); $processedText = (new FileEditor)->process($expectedInput, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } /** @test */ public function it_properly_escapes_a_string() { $input = file_get_contents(__DIR__ . '/fixtures/NeedsEscaping/input.php'); $expectedOutput = file_get_contents(__DIR__ . '/fixtures/NeedsEscaping/output.php'); $grammar = collect([ new Click([ [ 'name' => 'name', 'value' => 'foo', ], ], [], 'button', [ 'label' => "Let's go!", ]), new See([], [], 'span', [ 'text' => "Let's do it!", ]), ]); $processedText = (new FileEditor)->process($input, $grammar, 'testBasicExample'); $this->assertEquals($expectedOutput, $processedText); } } ================================================ FILE: tests/Grammar/ClickTest.php ================================================ "click", "attributes" => [ [ "name" => "id", "value" => "location", "isUnique" => true, ], [ "name" => "name", "value" => "country", "isUnique" => true, ], [ "name" => "class", "value" => "mt-1", "isUnique" => true, ], ], "parent" => [ ], "tag" => "select", "meta" => [ "type" => "select-one", "label" => "EU", ], ]; $click = Grammar::for($array); $this->assertEquals('select', $click->nameForParser()); $this->assertEquals([ new String_('country'), new String_('EU'), ], $click->arguments()); $this->assertEquals(new Pause(500), $click->pause()); } /** @test */ public function it_properly_builds_a_radio() { $array = [ "action" => "click", "attributes" => [ [ "name" => "id", "value" => "push_everything", "isUnique" => true, ], [ "name" => "name", "value" => "some_radio", "isUnique" => false, ], [ "name" => "type", "value" => "radio", "isUnique" => false, ], [ "name" => "class", "value" => "focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300", "isUnique" => false, ], ], "parent" => [ ], "tag" => "input", "meta" => [ "type" => "radio", "label" => "Option 1", ], ]; $click = Grammar::for($array); $this->assertEquals('radio', $click->nameForParser()); $this->assertEquals([ new String_('input[name=some_radio]'), new String_('Option 1'), ], $click->arguments()); $this->assertEquals(new Pause(500), $click->pause()); } } ================================================ FILE: tests/Grammar/FillTest.php ================================================ 'fill', 'attributes' => [ [ 'name' => 'name', 'value' => 'email', 'isUnique' => true, ], ], 'parent' => [], 'tag' => 'input', 'meta' => [ 'text' => 'myemail@gmail.com', ], ]); $this->assertEquals('type', $fill->nameForParser()); $this->assertEquals([ new String_('email'), new String_('myemail@gmail.com'), ], $fill->arguments()); $this->assertEquals(null, $fill->pause()); } /** @test */ public function it_properly_adds_a_pause_to_a_livewire_input() { $fill = Grammar::for([ 'action' => 'fill', 'attributes' => [ [ 'name' => 'name', 'value' => 'email', 'isUnique' => true, ], [ 'name' => 'wire:model', 'value' => 'email', 'isUnique' => true, ], ], 'parent' => [], 'tag' => 'input', 'meta' => [ 'text' => 'myemail@gmail.com', ], ]); $this->assertEquals('type', $fill->nameForParser()); $this->assertEquals([ new String_('email'), new String_('myemail@gmail.com'), ], $fill->arguments()); $this->assertEquals(new Pause(200), $fill->pause()); } /** @test */ public function it_uses_the_livewire_selector_when_name_is_not_unique() { $fill = Grammar::for([ 'action' => 'fill', 'attributes' => [ [ 'name' => 'name', 'value' => 'email', 'isUnique' => false, ], [ 'name' => 'wire:model', 'value' => 'userEmail', 'isUnique' => true, ], ], 'parent' => [], 'tag' => 'input', 'meta' => [ 'text' => 'myemail@gmail.com', ], ]); $this->assertEquals('type', $fill->nameForParser()); $this->assertEquals([ new String_('input[wire\:model=userEmail]'), new String_('myemail@gmail.com'), ], $fill->arguments()); $this->assertEquals(new Pause(200), $fill->pause()); } /** @test */ public function it_gives_priority_to_the_name_attribute() { $fill = Grammar::for([ 'action' => 'fill', 'attributes' => [ [ 'name' => 'id', 'value' => 'foo', 'isUnique' => true, ], [ 'name' => 'name', 'value' => 'email', 'isUnique' => true, ], [ 'name' => 'wire:model', 'value' => 'userEmail', 'isUnique' => true, ], ], 'parent' => [], 'tag' => 'input', 'meta' => [ 'text' => 'myemail@gmail.com', ], ]); $this->assertEquals('type', $fill->nameForParser()); $this->assertEquals([ new String_('email'), new String_('myemail@gmail.com'), ], $fill->arguments()); $this->assertEquals(new Pause(200), $fill->pause()); } } ================================================ FILE: tests/Grammar/SeeTest.php ================================================ 'see', 'attributes' => [], 'parent' => [], 'tag' => 'span', 'meta' => [ 'text' => "Some string that contains ' and '", ], ]); $this->assertEquals('assertSee', $fill->nameForParser()); $this->assertEquals([ new String_('Some string that contains \' and \''), ], $fill->arguments()); $this->assertEquals(null, $fill->pause()); } } ================================================ FILE: tests/MagicTestManagerTest.php ================================================ testFilePaths = [ __DIR__ . '/fixtures/Regular/input.php', __DIR__ . '/fixtures/WithActions/input.php', ]; $this->originalContents = [ file_get_contents($this->testFilePaths[0]), file_get_contents($this->testFilePaths[1]), ]; } public function tearDown(): void { foreach ($this->testFilePaths as $index => $path) { file_put_contents($path, $this->originalContents[$index]); } } /** @test */ public function it_replaces_the_content_of_a_file_with_actions() { $expectedOutput = file_get_contents(__DIR__ . '/fixtures/WithActions/output.php'); MagicTest::setOpenFile($this->testFilePaths[1]); MagicTest::setTestMethod('testBasicExample'); $input = file_get_contents(MagicTest::$file); $grammar = collect([ new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); (new MagicTestManager)->buildTest($grammar); $this->assertEquals($expectedOutput, file_get_contents(MagicTest::$file)); file_put_contents(MagicTest::$file, $input); } /** @test */ public function it_replaces_the_content_of_a_file_without_actions() { $expectedOutput = file_get_contents(__DIR__ . '/fixtures/Regular/output.php'); MagicTest::setOpenFile($this->testFilePaths[0]); MagicTest::setTestMethod('testBasicExample'); $input = file_get_contents(MagicTest::$file); $grammar = collect([ new Click([], [], 'a', ['text' => 'Log in']), new Click([], [], 'a', ['text' => 'Forgot your password?']), new See([], [], 'span', ['text' => 'Mateus']), ]); (new MagicTestManager)->buildTest($grammar); $this->assertEquals($expectedOutput, file_get_contents(MagicTest::$file)); file_put_contents(MagicTest::$file, $input); } } ================================================ FILE: tests/Parser/FileTest.php ================================================ expectException(InvalidFileException::class); $fixture = file_get_contents(__DIR__ . '/../fixtures/Errors/MissingMethod.php'); new File($fixture, 'testBasicExample'); } /** @test */ public function it_validates_a_class_missing_the_method_Call() { $this->expectException(InvalidFileException::class); $fixture = file_get_contents(__DIR__ . '/../fixtures/Errors/MissingMethodCall.php'); new File($fixture, 'testBasicExample'); } /** @test */ public function it_validates_a_class_missing_the_closure() { $this->expectException(InvalidFileException::class); $fixture = file_get_contents(__DIR__ . '/../fixtures/Errors/MissingClosure.php'); new File($fixture, 'testBasicExample'); } } ================================================ FILE: tests/Support/AttributeCollectionTest.php ================================================ 'id', 'value' => 'foo', ], [ 'name' => 'wire:model', 'value' => 'bar', ], [ 'name' => 'name', 'value' => 'baz', ], ]))->map(fn ($element) => new Attribute($element['name'], $element['value'])); $this->assertEquals(['name', 'id', 'wire:model'], $collection->reorderItems()->pluck('name')->toArray()); } /** @test */ public function it_reorders_items_and_gives_preference_to_dusk() { $collection = (new AttributeCollection([ [ 'name' => 'id', 'value' => 'foo', ], [ 'name' => 'wire:model', 'value' => 'bar', ], [ 'name' => 'dusk', 'value' => 'biz', ], [ 'name' => 'name', 'value' => 'baz', ], ]))->map(fn ($element) => new Attribute($element['name'], $element['value'])); $this->assertEquals(['dusk', 'name', 'id', 'wire:model'], $collection->reorderItems()->pluck('name')->toArray()); } } ================================================ FILE: tests/TestCase.php ================================================ browse(); } } ================================================ FILE: tests/fixtures/Finished/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Register') ->pause(500) ->type('name', 'Mateus Guimaraes') ->type('email', 'mateus@mateusguimaraes.com') ->type('password', 'password') ->type('password_confirmation', 'password') ->radio('input[name=some_radio]', 'Option 1') ->press('REGISTER') ->magic(); }); } } ================================================ FILE: tests/fixtures/Finished/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Register') ->pause(500) ->type('name', 'Mateus Guimaraes') ->type('email', 'mateus@mateusguimaraes.com') ->type('password', 'password') ->type('password_confirmation', 'password') ->radio('input[name=some_radio]', 'Option 1') ->press('REGISTER'); }); } } ================================================ FILE: tests/fixtures/Finished/output_with_click.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Register') ->pause(500) ->type('name', 'Mateus Guimaraes') ->type('email', 'mateus@mateusguimaraes.com') ->type('password', 'password') ->type('password_confirmation', 'password') ->radio('input[name=some_radio]', 'Option 1') ->press('REGISTER'); }); } } ================================================ FILE: tests/fixtures/Livewire/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->magic(); }); } } ================================================ FILE: tests/fixtures/Livewire/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->pause(500) ->type('name', 'Mateus') ->pause(200) ->type('email', 'mateus@mateusguimaraes.com') ->pause(200) ->magic(); }); } } ================================================ FILE: tests/fixtures/MissingActions/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Log in') ->clickLink('Forgot your password?') ->assertSee('Mateus') ->magic(); }); } } ================================================ FILE: tests/fixtures/MissingActions/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Log in') ->clickLink('Forgot your password?') ->assertSee('Mateus') ->magic(); }); } } ================================================ FILE: tests/fixtures/NeedsEscaping/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->magic(); }); } } ================================================ FILE: tests/fixtures/NeedsEscaping/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->press('Let\'s go!') ->pause(500) ->assertSee('Let\'s do it!') ->magic(); }); } } ================================================ FILE: tests/fixtures/Regular/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->magic(); }); } } ================================================ FILE: tests/fixtures/Regular/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->clickLink('Log in') ->pause(500) ->clickLink('Forgot your password?') ->pause(500) ->assertSee('Mateus') ->magic(); }); } } ================================================ FILE: tests/fixtures/WithActions/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->magic(); }); } } ================================================ FILE: tests/fixtures/WithActions/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->pause(500) ->clickLink('Forgot your password?') ->pause(500) ->assertSee('Mateus') ->magic(); }); } } ================================================ FILE: tests/fixtures/WithActionsAndInlineCode/input.php ================================================ browse(function (Browser $browser) { $browser->visit('/')->assertSee('Laravel')->clickLink('Log in')->magic(); }); } } ================================================ FILE: tests/fixtures/WithActionsAndInlineCode/newFile.php ================================================ ================================================ FILE: tests/fixtures/WithActionsAndInlineCode/output.php ================================================ browse(function (Browser $browser) { $browser->visit('/')->assertSee('Laravel')->clickLink('Log in') ->pause(500) ->clickLink('Forgot your password?') ->pause(500) ->assertSee('Mateus')->magic(); }); } } ================================================ FILE: tests/fixtures/WithActionsAndTwoClosures/input.php ================================================ browse(function (Browser $browser) { }); $this->browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->magic(); }); } } ================================================ FILE: tests/fixtures/WithActionsAndTwoClosures/output.php ================================================ browse(function (Browser $browser) { }); $this->browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel') ->clickLink('Log in') ->pause(500) ->clickLink('Forgot your password?') ->pause(500) ->assertSee('Mateus') ->magic(); }); } } ================================================ FILE: webpack.mix.js ================================================ const mix = require('laravel-mix'); mix.js('js/magic_test.js', 'dist')