Lazy Load by WP Rocket - Version 1.3

Version Description

  • 2017-09-01
  • Improve HTML parsing of images and iframes to be faster and more efficient
  • Make the lazyload compatible with fitVids for iframes
  • Don't apply lazyload on AMP pages (compatible with AMP plugin from Automattic)
  • Use about:blank as default iframe placeholder to prevent warning in browser console
  • Don't apply lazyload on upPrev thumbnail
Download this release

Release Info

Developer wp_media
Plugin Icon 128x128 Lazy Load by WP Rocket
Version 1.3
Comparing to
See all releases

Code changes from version 1.2.1 to 1.3

Files changed (74) hide show
  1. 3rd-party/3rd-party.php +4 -0
  2. 3rd-party/amp.php +16 -0
  3. admin/admin.php +12 -7
  4. readme.txt +34 -21
  5. rocket-lazy-load.php +161 -137
  6. vendor/autoload.php +7 -0
  7. vendor/composer/ClassLoader.php +445 -0
  8. vendor/composer/LICENSE +21 -0
  9. vendor/composer/autoload_classmap.php +9 -0
  10. vendor/composer/autoload_namespaces.php +11 -0
  11. vendor/composer/autoload_psr4.php +9 -0
  12. vendor/composer/autoload_real.php +52 -0
  13. vendor/composer/autoload_static.php +33 -0
  14. vendor/composer/installed.json +101 -0
  15. vendor/paquettg/php-html-parser/.scrutinizer.yml +35 -0
  16. vendor/paquettg/php-html-parser/.travis.yml +19 -0
  17. vendor/paquettg/php-html-parser/CHANGELOG.md +114 -0
  18. vendor/paquettg/php-html-parser/CONTRIBUTING.md +21 -0
  19. vendor/paquettg/php-html-parser/LICENSE.md +21 -0
  20. vendor/paquettg/php-html-parser/README.md +219 -0
  21. vendor/paquettg/php-html-parser/composer.json +32 -0
  22. vendor/paquettg/php-html-parser/phpunit.php +28 -0
  23. vendor/paquettg/php-html-parser/phpunit.xml +27 -0
  24. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Content.php +252 -0
  25. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Curl.php +41 -0
  26. vendor/paquettg/php-html-parser/src/PHPHtmlParser/CurlInterface.php +19 -0
  27. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom.php +648 -0
  28. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/AbstractNode.php +410 -0
  29. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/ArrayNode.php +41 -0
  30. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/Collection.php +168 -0
  31. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/HtmlNode.php +200 -0
  32. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/InnerNode.php +376 -0
  33. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/LeafNode.php +13 -0
  34. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/MockNode.php +54 -0
  35. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/Tag.php +270 -0
  36. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/TextNode.php +105 -0
  37. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/ChildNotFoundException.php +12 -0
  38. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/CircularException.php +11 -0
  39. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/CurlException.php +11 -0
  40. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/EmptyCollectionException.php +11 -0
  41. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/NotLoadedException.php +11 -0
  42. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/ParentNotFoundException.php +11 -0
  43. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/StrictException.php +11 -0
  44. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/UnknownChildTypeException.php +11 -0
  45. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Options.php +87 -0
  46. vendor/paquettg/php-html-parser/src/PHPHtmlParser/Selector.php +378 -0
  47. vendor/paquettg/php-html-parser/src/PHPHtmlParser/StaticDom.php +113 -0
  48. vendor/paquettg/php-html-parser/tests/CollectionTest.php +115 -0
  49. vendor/paquettg/php-html-parser/tests/ContentTest.php +94 -0
  50. vendor/paquettg/php-html-parser/tests/DomTest.php +322 -0
  51. vendor/paquettg/php-html-parser/tests/Node/ChildrenTest.php +118 -0
  52. vendor/paquettg/php-html-parser/tests/Node/HtmlTest.php +459 -0
  53. vendor/paquettg/php-html-parser/tests/Node/ParentTest.php +219 -0
  54. vendor/paquettg/php-html-parser/tests/Node/TagTest.php +156 -0
  55. vendor/paquettg/php-html-parser/tests/Node/TextTest.php +32 -0
  56. vendor/paquettg/php-html-parser/tests/Options/CleanupTest.php +73 -0
  57. vendor/paquettg/php-html-parser/tests/Options/PreserveLineBreaks.php +30 -0
  58. vendor/paquettg/php-html-parser/tests/Options/StrictTest.php +55 -0
  59. vendor/paquettg/php-html-parser/tests/Options/WhitespaceTextNodeTest.php +28 -0
  60. vendor/paquettg/php-html-parser/tests/OptionsTest.php +43 -0
  61. vendor/paquettg/php-html-parser/tests/SelectorTest.php +206 -0
  62. vendor/paquettg/php-html-parser/tests/StaticDomTest.php +76 -0
  63. vendor/paquettg/php-html-parser/tests/files/big.html +1464 -0
  64. vendor/paquettg/php-html-parser/tests/files/horrible.html +301 -0
  65. vendor/paquettg/php-html-parser/tests/files/small.html +117 -0
  66. vendor/paquettg/string-encode/.travis.yml +14 -0
  67. vendor/paquettg/string-encode/CONTRIBUTING.md +21 -0
  68. vendor/paquettg/string-encode/README.md +28 -0
  69. vendor/paquettg/string-encode/composer.json +28 -0
  70. vendor/paquettg/string-encode/phpunit.php +28 -0
  71. vendor/paquettg/string-encode/phpunit.xml +27 -0
  72. vendor/paquettg/string-encode/src/stringEncode/Encode.php +121 -0
  73. vendor/paquettg/string-encode/src/stringEncode/Exception.php +4 -0
  74. vendor/paquettg/string-encode/tests/EncodeTest.php +28 -0
3rd-party/3rd-party.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
+
4
+ require ROCKET_LL_3RD_PARTY_PATH . 'amp.php';
3rd-party/amp.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
+
4
+ /**
5
+ * Removes LazyLoad when on an AMP version of a post with the AMP for WordPress plugin from Auttomatic
6
+ *
7
+ * @since 1.2.2
8
+ *
9
+ * @author Remy Perona
10
+ */
11
+ function rocket_lazyload_disable_on_amp() {
12
+ if ( defined( 'AMP_QUERY_VAR' ) && function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
13
+ add_filter( 'do_rocket_lazyload', '__return_false' );
14
+ }
15
+ }
16
+ add_action( 'wp', 'rocket_lazyload_disable_on_amp' );
admin/admin.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php
2
- defined( 'ABSPATH' ) or die( 'Cheatin\' uh?' );
3
 
4
  /**
5
  * Add Rocket LazyLoad settings page to Settings menu.
@@ -67,7 +67,10 @@ function rocket_lazyload_options_output() {
67
  </div>
68
  <?php $rocket_lazyload_rate_url = 'https://wordpress.org/support/plugin/rocket-lazy-load/reviews/?rate=5#postform'; ?>
69
  <p class="rocket-lazyload-rate-us">
70
- <?php printf( __( '%1$sDo you like this plugin?%2$s Please take a few seconds to %3$srate it on WordPress.org%4$s!', 'rocket-lazyload' ), '<strong>', '</strong><br>', '<a href="' . $rocket_lazyload_rate_url . '">', '</a>' ); ?>
 
 
 
71
  <br>
72
  <a class="stars" href="<?php echo $rocket_lazyload_rate_url; ?>"><?php echo str_repeat( '<span class="dashicons dashicons-star-filled"></span>', 5 ); ?></a>
73
  </p>
@@ -92,19 +95,21 @@ function rocket_lazyload_options_output() {
92
  </ul>
93
  </fieldset>
94
  <?php
95
- settings_fields( 'rocket_lazyload' );
96
- submit_button( __( '✓ Save changes', 'rocket-lazyload' ) );
97
  ?>
98
  </form>
99
  <div class="rocket-lazyload-cross-sell">
100
  <h2 class="rocket-lazyload-cross-sell-title"><?php _e( 'Need To Boost Your Speed Even More?', 'rocket-lazyload' ); ?></h2>
101
  <div class="rocket-lazyload-ads">
102
- <a href="https://wp-rocket.me?utm_source=wp_plugin&utm_medium=rocket_lazyload"><img src="<?php echo ROCKET_LL_ASSETS_URL ?>img/wp-rocket@2x.jpg" alt="WP Rocket" width="393" height="180"></a>
103
  <?php if ( ! is_plugin_active( 'imagify/imagify.php' ) ) : ?>
104
- <a href="https://imagify.io?utm_source=wp_plugin&utm_medium=rocket_lazyload"><img src="<?php echo ROCKET_LL_ASSETS_URL ?>img/imagify@2x.jpg" alt="Imagify" width="393" height="180"></a>
105
  <?php endif; ?>
106
  </div>
107
  </div>
108
  </div>
109
  </div>
110
- <?php }
 
 
1
  <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
 
4
  /**
5
  * Add Rocket LazyLoad settings page to Settings menu.
67
  </div>
68
  <?php $rocket_lazyload_rate_url = 'https://wordpress.org/support/plugin/rocket-lazy-load/reviews/?rate=5#postform'; ?>
69
  <p class="rocket-lazyload-rate-us">
70
+ <?php
71
+ // Translators: %1$s is a <strong> tag, %2$s is </strong><br>, %3$s is the complete link tag to Rocket Lazy Load review form, %4$s is the closing </a> tag.
72
+ printf( __( '%1$sDo you like this plugin?%2$s Please take a few seconds to %3$srate it on WordPress.org%4$s!', 'rocket-lazyload' ), '<strong>', '</strong><br>', '<a href="' . $rocket_lazyload_rate_url . '">', '</a>' );
73
+ ?>
74
  <br>
75
  <a class="stars" href="<?php echo $rocket_lazyload_rate_url; ?>"><?php echo str_repeat( '<span class="dashicons dashicons-star-filled"></span>', 5 ); ?></a>
76
  </p>
95
  </ul>
96
  </fieldset>
97
  <?php
98
+ settings_fields( 'rocket_lazyload' );
99
+ submit_button( __( '✓ Save changes', 'rocket-lazyload' ) );
100
  ?>
101
  </form>
102
  <div class="rocket-lazyload-cross-sell">
103
  <h2 class="rocket-lazyload-cross-sell-title"><?php _e( 'Need To Boost Your Speed Even More?', 'rocket-lazyload' ); ?></h2>
104
  <div class="rocket-lazyload-ads">
105
+ <a href="https://wp-rocket.me?utm_source=wp_plugin&utm_medium=rocket_lazyload"><img src="<?php echo ROCKET_LL_ASSETS_URL; ?>img/wp-rocket@2x.jpg" alt="WP Rocket" width="393" height="180"></a>
106
  <?php if ( ! is_plugin_active( 'imagify/imagify.php' ) ) : ?>
107
+ <a href="https://imagify.io?utm_source=wp_plugin&utm_medium=rocket_lazyload"><img src="<?php echo ROCKET_LL_ASSETS_URL; ?>img/imagify@2x.jpg" alt="Imagify" width="393" height="180"></a>
108
  <?php endif; ?>
109
  </div>
110
  </div>
111
  </div>
112
  </div>
113
+ <?php
114
+ }
115
+
readme.txt CHANGED
@@ -1,23 +1,21 @@
1
  === Rocket Lazy Load ===
2
  Contributors: creativejuiz, tabrisrp, wp_media
3
- Tags: lazyload, lazy load, images, thumbnail, thumbnails, smiley, smilies, avatar, gravatar
4
  Requires at least: 3.0
5
  Tested up to: 4.8.1
6
- Stable tag: 1.2.1
7
 
8
- The tiny Lazy Load script for WordPress without jQuery or others libraries.
9
 
10
  == Description ==
11
 
12
- Lazy Load displays images on a page only when they are visible to the user. This reduces the number of HTTP requests mechanism and improves the loading time.
13
 
14
- This plugin works on thumbnails, all images in a post content or in a widget text, avatars and smilies. No JavaScript library such as jQuery is used and the script weight is less than 6kb.
15
-
16
- Simply install the plugin to enjoy a faster website. No options are available: you install it and the plugin takes care of everything.
17
 
18
  = Related Plugins =
19
  * <a href="https://wordpress.org/plugins/imagify/">Imagify</a>: Best Image Optimizer to speed up your website with lighter images.
20
- * <a href="http://wp-rocket.me">WP Rocket</a>: Best caching plugin to speed-up your WordPress website.
21
 
22
  == Installation ==
23
 
@@ -28,9 +26,10 @@ Simply install the plugin to enjoy a faster website. No options are available: y
28
 
29
  = How can i deactivate Lazy Load on some pages? =
30
 
31
- You can use <em>do_rocket_lazyload</em> filter.
 
 
32
 
33
- Here, an example to put in functions.php files :
34
  `
35
  add_action( 'wp', 'deactivate_rocket_lazyload_on_single' );
36
  function deactivate_rocket_lazyload_on_single() {
@@ -42,25 +41,39 @@ function deactivate_rocket_lazyload_on_single() {
42
 
43
  = How can i deactivate Lazy Load on some images? =
44
 
45
- Simply add a 'data-no-lazy="1"' property in you IMG tag.
 
 
 
 
 
 
46
 
47
  == Changelog ==
 
 
 
 
 
 
 
 
48
  = 1.2.1 =
49
- * 22 aug. 2017
50
  * Fix missing lazyload script
51
  * Don't lazyload for images in REST API requests
52
 
53
  = 1.2 =
54
- * 22 aug. 2017
55
  * Update lazyload script to latest version
56
  * Change the way the script is loaded
57
 
58
  = 1.1.1 =
59
- * 13 feb. 2017
60
  * Bug fix: Remove use of short tag to prevent 500 error on some installations
61
 
62
  = 1.1 =
63
- * 12 feb. 2017
64
  * *New*
65
  * JS library updated
66
  * Support for iFrame
@@ -68,27 +81,27 @@ Simply add a 'data-no-lazy="1"' property in you IMG tag.
68
  * New options page
69
 
70
  = 1.0.4 =
71
- * 28 apr. 2015
72
  * Bug Fix: Resolved a conflict between LazyLoad & Emoji since WordPress 4.2
73
 
74
  = 1.0.3 =
75
- * 08 jan. 2015
76
  * Bug Fix: Don't apply LazyLoad on captcha from Really Simple CAPTCHA to prevent conflicts.
77
 
78
  = 1.0.2 =
79
- * 28 dec. 2014
80
  * Improvement: Add « rocket_lazyload_html » filter to manage the output that will be printed.
81
 
82
  = 1.0.1.1 =
83
- * 25 jul. 2014
84
  * Fix stupid error with new regex in 1.0.1
85
 
86
  = 1.0.1 =
87
- * 16 jul. 2014
88
  * Bug Fix: when a IMG tag or content (widget or post) contains the string "data-no-lazy", all IMG tags were ignored instead of one.
89
  * Security fix: The preg_replace() could lead to a XSS vuln, thanks to Alexander Concha
90
  * Code compliance
91
 
92
  = 1.0 =
93
- * 01 jan. 2014
94
  * Initial release.
1
  === Rocket Lazy Load ===
2
  Contributors: creativejuiz, tabrisrp, wp_media
3
+ Tags: lazyload, lazy load, images, iframes, thumbnail, thumbnails, smiley, smilies, avatar, gravatar
4
  Requires at least: 3.0
5
  Tested up to: 4.8.1
6
+ Stable tag: 1.3
7
 
8
+ The tiny Lazy Load script for WordPress without jQuery, works for images and iframes.
9
 
10
  == Description ==
11
 
12
+ Lazy Load displays images and/or iframes on a page only when they are visible to the user. This reduces the number of HTTP requests mechanism and improves the loading time.
13
 
14
+ This plugin works on thumbnails, all images in a post content or in a widget text, avatars, smilies and iFrames. No JavaScript library such as jQuery is used and the script weight is less than 10KB.
 
 
15
 
16
  = Related Plugins =
17
  * <a href="https://wordpress.org/plugins/imagify/">Imagify</a>: Best Image Optimizer to speed up your website with lighter images.
18
+ * <a href="https://wp-rocket.me">WP Rocket</a>: Best caching plugin to speed-up your WordPress website.
19
 
20
  == Installation ==
21
 
26
 
27
  = How can i deactivate Lazy Load on some pages? =
28
 
29
+ You can use the `do_rocket_lazyload` filter.
30
+
31
+ Here is an example to put in functions.php files that disable lazyload on posts:
32
 
 
33
  `
34
  add_action( 'wp', 'deactivate_rocket_lazyload_on_single' );
35
  function deactivate_rocket_lazyload_on_single() {
41
 
42
  = How can i deactivate Lazy Load on some images? =
43
 
44
+ Simply add a `data-no-lazy="1"` property in you `img` or `iframe` tag.
45
+
46
+ You can also use the filters `rocket_lazyload_excluded_attributes` or `rocket_lazyload_excluded_src` to exclude specific patterns.
47
+
48
+ = I use plugin X and my images don't show anymore =
49
+
50
+ Some plugins are not compatible without lazy loading. Please open a support thread, and we will see how we can solve the issue by excluding lazy loading for this plugin.
51
 
52
  == Changelog ==
53
+ = 1.3 =
54
+ * 2017-09-01
55
+ * Improve HTML parsing of images and iframes to be faster and more efficient
56
+ * Make the lazyload compatible with fitVids for iframes
57
+ * Don't apply lazyload on AMP pages (compatible with AMP plugin from Automattic)
58
+ * Use about:blank as default iframe placeholder to prevent warning in browser console
59
+ * Don't apply lazyload on upPrev thumbnail
60
+
61
  = 1.2.1 =
62
+ * 2017-08-22
63
  * Fix missing lazyload script
64
  * Don't lazyload for images in REST API requests
65
 
66
  = 1.2 =
67
+ * 2017-08-22
68
  * Update lazyload script to latest version
69
  * Change the way the script is loaded
70
 
71
  = 1.1.1 =
72
+ * 2017-02-13
73
  * Bug fix: Remove use of short tag to prevent 500 error on some installations
74
 
75
  = 1.1 =
76
+ * 2017-02-12
77
  * *New*
78
  * JS library updated
79
  * Support for iFrame
81
  * New options page
82
 
83
  = 1.0.4 =
84
+ * 2015-04-28
85
  * Bug Fix: Resolved a conflict between LazyLoad & Emoji since WordPress 4.2
86
 
87
  = 1.0.3 =
88
+ * 2015-01-08
89
  * Bug Fix: Don't apply LazyLoad on captcha from Really Simple CAPTCHA to prevent conflicts.
90
 
91
  = 1.0.2 =
92
+ * 2014-12-28
93
  * Improvement: Add « rocket_lazyload_html » filter to manage the output that will be printed.
94
 
95
  = 1.0.1.1 =
96
+ * 2014-07-25
97
  * Fix stupid error with new regex in 1.0.1
98
 
99
  = 1.0.1 =
100
+ * 2014-07-16
101
  * Bug Fix: when a IMG tag or content (widget or post) contains the string "data-no-lazy", all IMG tags were ignored instead of one.
102
  * Security fix: The preg_replace() could lead to a XSS vuln, thanks to Alexander Concha
103
  * Code compliance
104
 
105
  = 1.0 =
106
+ * 2014-01-01
107
  * Initial release.
rocket-lazy-load.php CHANGED
@@ -1,19 +1,20 @@
1
  <?php
2
- defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
 
4
  /**
5
  * Plugin Name: Rocket Lazy Load
6
  * Plugin URI: http://wordpress.org/plugins/rocket-lazy-load/
7
  * Description: The tiny Lazy Load script for WordPress without jQuery or others libraries.
8
- * Version: 1.2.1
 
9
  * Author: WP Media
10
  * Author URI: https://wp-rocket.me
11
  * Text Domain: rocket-lazy-load
12
  * Domain Path: /languages
13
  *
14
- * Copyright 2015 WP Media
15
  *
16
- * This program is free software; you can redistribute it and/or modify
17
  * it under the terms of the GNU General Public License as published by
18
  * the Free Software Foundation; either version 2 of the License, or
19
  * (at your option) any later version.
@@ -24,10 +25,11 @@ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
24
  * GNU General Public License for more details.
25
  *
26
  * You should have received a copy of the GNU General Public License
27
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
28
  */
29
- define( 'ROCKET_LL_VERSION', '1.2' );
30
  define( 'ROCKET_LL_PATH', realpath( plugin_dir_path( __FILE__ ) ) . '/' );
 
31
  define( 'ROCKET_LL_ASSETS_URL', plugin_dir_url( __FILE__ ) . 'assets/' );
32
  define( 'ROCKET_LL_FRONT_JS_URL', ROCKET_LL_ASSETS_URL . 'js/' );
33
  define( 'ROCKET_LL_JS_VERSION' , '8.0.3' );
@@ -42,11 +44,42 @@ define( 'ROCKET_LL_JS_VERSION' , '8.0.3' );
42
  function rocket_lazyload_init() {
43
  load_plugin_textdomain( 'rocket-lazy-load', false, basename( dirname( __FILE__ ) ) . '/languages/' );
44
 
 
 
 
45
  if ( is_admin() ) {
46
- require( ROCKET_LL_PATH . 'admin/admin.php' );
47
  }
48
  }
49
- add_action( 'plugins_loaded', 'rocket_lazyload_init' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  /**
52
  * A wrapper to easily get rocket lazyload option
@@ -84,26 +117,16 @@ function rocket_lazyload_script() {
84
  class_loading: "lazyloading",
85
  class_loaded: "lazyloaded",
86
  threshold: $threshold,
87
- callback_set: function(element) {
88
- //todo: check fitvids compatibility (class or data-attribute)
89
- if ( element.tagName === "IFRAME" && element.classList.contains("fitvidscompatible") ) {
90
- if ( element.classList.contains("lazyloaded") ) {
91
- //todo: check if $.fn.fitvids() is available
92
- if ( typeof $ === "function" ) {
93
- $( element ).parent().fitVids();
94
- }
95
- } else {
96
- var temp = setInterval( function() {
97
- //todo: check if $.fn.fitvids() is available
98
- if ( element.classList.contains("lazyloaded") && typeof $ === "function" ) {
99
- $( element ).parent().fitVids();
100
- clearInterval( temp );
101
- } else {
102
- clearInterval( temp );
103
  }
104
- }, 50 );
105
  }
106
- } // if element is an iframe
107
  }
108
  };
109
  </script>
@@ -169,99 +192,111 @@ function rocket_lazyload_images( $html ) {
169
  return $html;
170
  }
171
 
172
- $html = preg_replace_callback( '#<img([^>]*) src=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))([^>]*)>#', 'rocket_lazyload_replace_callback', $html );
 
 
173
 
174
- return $html;
175
- }
176
- add_filter( 'get_avatar' , 'rocket_lazyload_images', PHP_INT_MAX );
177
- add_filter( 'the_content' , 'rocket_lazyload_images', PHP_INT_MAX );
178
- add_filter( 'widget_text' , 'rocket_lazyload_images', PHP_INT_MAX );
179
- add_filter( 'get_image_tag' , 'rocket_lazyload_images', PHP_INT_MAX );
180
- add_filter( 'post_thumbnail_html', 'rocket_lazyload_images', PHP_INT_MAX );
181
 
182
- /**
183
- * Used to check if we have to LazyLoad this or not
184
- *
185
- * @since 1.1 Don't apply LazyLoad on images from WP Retina x2
186
- * @since 1.0.1
187
- *
188
- * @param string $matches a string matching the pattern to find images in HTML code.
189
- * @return string Updated string with lazyload data
190
- */
191
- function rocket_lazyload_replace_callback( $matches ) {
192
 
193
- if ( function_exists( 'wr2x_picture_rewrite' ) ) {
194
- if ( wr2x_get_retina( trailingslashit( ABSPATH ) . wr2x_get_pathinfo_from_image_src( trim( $matches[2], '"' ) ) ) ) {
195
- return $matches[0];
196
  }
197
- }
198
 
199
- $excluded_attributes = apply_filters( 'rocket_lazyload_excluded_attributes', array(
200
- 'data-no-lazy=',
201
- 'data-lazy-original=',
202
- 'data-lazy-src=',
203
- 'data-lazysrc=',
204
- 'data-lazyload=',
205
- 'data-bgposition=',
206
- 'data-envira-src=',
207
- 'fullurl=',
208
- 'lazy-slider-img=',
209
- 'data-srcset=',
210
- 'class="ls-l',
211
- 'class="ls-bg',
212
- ) );
213
 
214
- $excluded_src = apply_filters( 'rocket_lazyload_excluded_src', array(
215
- '/wpcf7_captcha/',
216
- 'timthumb.php?src',
217
- ) );
218
 
219
- if ( rocket_is_excluded_lazyload( $matches[1] . $matches[3], $excluded_attributes ) || rocket_is_excluded_lazyload( $matches[2], $excluded_src ) ) {
220
- return $matches[0];
221
- }
222
 
223
- /**
224
- * Filter the LazyLoad placeholder on src attribute
225
- *
226
- * @since 1.1
227
- *
228
- * @param string $placeholder Placeholder that will be printed.
229
- */
230
- $placeholder = apply_filters( 'rocket_lazyload_placeholder', 'data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=' );
 
 
 
231
 
232
- $html = sprintf( '<img%1$s src="%4$s" data-lazy-src=%2$s%3$s>', $matches[1], $matches[2], $matches[3], $placeholder );
 
 
 
233
 
234
- $html_noscript = sprintf( '<noscript><img%1$s src=%2$s%3$s></noscript>', $matches[1], $matches[2], $matches[3] );
 
 
 
235
 
236
- /**
237
- * Filter the LazyLoad HTML output
238
- *
239
- * @since 1.0.2
240
- *
241
- * @param array $html Output that will be printed
242
- */
243
- $html = apply_filters( 'rocket_lazyload_html', $html, true );
244
 
245
- return $html . $html_noscript;
 
 
 
 
246
  }
 
 
 
 
 
247
 
248
  /**
249
  * Determine if the current image should be excluded from lazyload
250
  *
 
251
  * @since 1.1
252
  * @author Remy Perona
253
  *
254
- * @param string $string String to search.
255
- * @param array $excluded_values Array of excluded values to search in the string.
256
  * @return bool True if one of the excluded values was found, false otherwise
257
  */
258
- function rocket_is_excluded_lazyload( $string, $excluded_values ) {
259
- foreach ( $excluded_values as $excluded_value ) {
260
- if ( strpos( $string, $excluded_value ) !== false ) {
261
  return true;
262
  }
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  return false;
266
  }
267
 
@@ -383,28 +418,6 @@ function rocket_translate_smiley( $matches ) {
383
 
384
  }
385
 
386
- /**
387
- * Compatibility with images with srcset attribute
388
- *
389
- * @since 1.1
390
- * @author Geoffrey Crofte (code from WP Rocket plugin)
391
- *
392
- * @param string $html the HTML code to parse.
393
- * @return string the updated HTML code
394
- */
395
- function rocket_lazyload_on_srcset( $html ) {
396
- if ( preg_match( '/srcset=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))/i', $html ) ) {
397
- $html = str_replace( 'srcset=', 'data-lazy-srcset=', $html );
398
- }
399
-
400
- if ( preg_match( '/sizes=("(?:[^"]+)"|\'(?:[^\']+)\'|(?:[^ >]+))/i', $html ) ) {
401
- $html = str_replace( 'sizes=', 'data-lazy-sizes=', $html );
402
- }
403
-
404
- return $html;
405
- }
406
- add_filter( 'rocket_lazyload_html', 'rocket_lazyload_on_srcset' );
407
-
408
  /**
409
  * Replace iframes by LazyLoad
410
  *
@@ -416,50 +429,61 @@ add_filter( 'rocket_lazyload_html', 'rocket_lazyload_on_srcset' );
416
  */
417
  function rocket_lazyload_iframes( $html ) {
418
  // Don't LazyLoad if process is stopped for these reasons.
419
- if ( ! rocket_lazyload_get_option( 'iframes' ) || ! apply_filters( 'do_rocket_lazyload_iframes', true ) || is_feed() || is_preview() || empty( $html ) || ( defined( 'DONOTLAZYLOAD' ) && DONOTLAZYLOAD ) ) {
420
  return $html;
421
  }
422
 
423
- $matches = array();
424
- preg_match_all( '/<iframe\s+.*?>/', $html, $matches );
 
 
 
 
 
425
 
426
- foreach ( $matches[0] as $k => $iframe ) {
 
427
 
428
  // Don't mess with the Gravity Forms ajax iframe.
429
- if ( strpos( $iframe, 'gform_ajax_frame' ) ) {
430
  continue;
431
  }
432
 
433
  // Don't lazyload if iframe has data-no-lazy attribute.
434
- if ( strpos( $iframe, 'data-no-lazy=' ) ) {
435
  continue;
436
  }
437
 
438
- /**
439
- * Filter the LazyLoad placeholder on src attribute
440
- *
441
- * @since 1.1
442
- *
443
- * @param string $placeholder placeholder that will be printed.
444
- */
445
- $placeholder = apply_filters( 'rocket_lazyload_placeholder', 'data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=' );
446
 
447
- // todo: add "fitvids compatible" class or data-attribute to check in JS (see JS L.57).
448
- $iframe = preg_replace( '/<iframe(.*?)src=/is', '<iframe$1src="' . $placeholder . '" data-lazy-src=', $iframe );
 
449
 
450
- $html = str_replace( $matches[0][ $k ], $iframe, $html );
 
 
451
 
452
  /**
453
- * Filter the LazyLoad HTML output on iframes
454
  *
455
  * @since 1.1
456
  *
457
- * @param array $html Output that will be printed.
458
- */
459
- $html = apply_filters( 'rocket_lazyload_iframe_html', $html );
 
 
 
 
 
 
 
 
 
460
  }
461
 
462
- return $html;
463
  }
464
  add_filter( 'the_content', 'rocket_lazyload_iframes', PHP_INT_MAX );
465
  add_filter( 'widget_text', 'rocket_lazyload_iframes', PHP_INT_MAX );
1
  <?php
2
+ defined( 'ABSPATH' ) || die( 'Cheatin\' uh?' );
3
 
4
  /**
5
  * Plugin Name: Rocket Lazy Load
6
  * Plugin URI: http://wordpress.org/plugins/rocket-lazy-load/
7
  * Description: The tiny Lazy Load script for WordPress without jQuery or others libraries.
8
+ * Version: 1.3
9
+ * Requires PHP: 5.4
10
  * Author: WP Media
11
  * Author URI: https://wp-rocket.me
12
  * Text Domain: rocket-lazy-load
13
  * Domain Path: /languages
14
  *
15
+ * Copyright 2015-2017 WP Media
16
  *
17
+ * This program is free software; you can redistribute it and/or modify
18
  * it under the terms of the GNU General Public License as published by
19
  * the Free Software Foundation; either version 2 of the License, or
20
  * (at your option) any later version.
25
  * GNU General Public License for more details.
26
  *
27
  * You should have received a copy of the GNU General Public License
28
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
29
  */
30
+ define( 'ROCKET_LL_VERSION', '1.3' );
31
  define( 'ROCKET_LL_PATH', realpath( plugin_dir_path( __FILE__ ) ) . '/' );
32
+ define( 'ROCKET_LL_3RD_PARTY_PATH', ROCKET_LL_PATH . '3rd-party/' );
33
  define( 'ROCKET_LL_ASSETS_URL', plugin_dir_url( __FILE__ ) . 'assets/' );
34
  define( 'ROCKET_LL_FRONT_JS_URL', ROCKET_LL_ASSETS_URL . 'js/' );
35
  define( 'ROCKET_LL_JS_VERSION' , '8.0.3' );
44
  function rocket_lazyload_init() {
45
  load_plugin_textdomain( 'rocket-lazy-load', false, basename( dirname( __FILE__ ) ) . '/languages/' );
46
 
47
+ require_once ROCKET_LL_PATH . 'vendor/autoload.php';
48
+ require ROCKET_LL_3RD_PARTY_PATH . '3rd-party.php';
49
+
50
  if ( is_admin() ) {
51
+ require ROCKET_LL_PATH . 'admin/admin.php';
52
  }
53
  }
54
+
55
+ if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
56
+ /**
57
+ * Warning if PHP version is less than 5.4.
58
+ *
59
+ * @since 1.3
60
+ */
61
+ function rocket_lazyload_php_warning() {
62
+ echo '<div class="error"><p>' . __( 'Rocket LazyLoad requires PHP 5.4 to function properly. Please upgrade PHP. The Plugin has been auto-deactivated.', 'rocket-lazy-load' ) . '</p></div>';
63
+ if ( isset( $_GET['activate'] ) ) {
64
+ unset( $_GET['activate'] );
65
+ }
66
+ }
67
+ add_action( 'admin_notices', 'rocket_lazyload_php_warning' );
68
+
69
+ /**
70
+ * Deactivate plugin if needed.
71
+ *
72
+ * @since 1.3
73
+ */
74
+ function rocket_lazyload_deactivate_self() {
75
+ deactivate_plugins( plugin_basename( __FILE__ ) );
76
+ }
77
+ add_action( 'admin_init', 'rocket_lazyload_deactivate_self' );
78
+
79
+ return;
80
+ } else {
81
+ add_action( 'plugins_loaded', 'rocket_lazyload_init' );
82
+ }
83
 
84
  /**
85
  * A wrapper to easily get rocket lazyload option
117
  class_loading: "lazyloading",
118
  class_loaded: "lazyloaded",
119
  threshold: $threshold,
120
+ callback_load: function(element) {
121
+ if ( element.tagName === "IFRAME" && element.dataset.rocketLazyload == "fitvidscompatible" ) {
122
+ if (element.classList.contains("lazyloaded") ) {
123
+ if (typeof window.jQuery != 'undefined') {
124
+ if (jQuery.fn.fitVids) {
125
+ jQuery(element).parent().fitVids();
 
 
 
 
 
 
 
 
 
 
126
  }
127
+ }
128
  }
129
+ }
130
  }
131
  };
132
  </script>
192
  return $html;
193
  }
194
 
195
+ $dom = new PHPHtmlParser\Dom();
196
+ $dom->load( $html );
197
+ $images = $dom->getElementsByTag( 'img' );
198
 
199
+ if ( ! $images ) {
200
+ return $html;
201
+ }
 
 
 
 
202
 
203
+ foreach ( $images as $image ) {
204
+ $image_attributes = $image->getAttributes();
 
 
 
 
 
 
 
 
205
 
206
+ if ( rocket_is_excluded_lazyload( $image_attributes ) ) {
207
+ continue;
 
208
  }
 
209
 
210
+ $img = new PHPHtmlParser\Dom\Tag( 'img' );
 
 
 
 
 
 
 
 
 
 
 
 
 
211
 
212
+ foreach ( $image_attributes as $key => $value ) {
213
+ $img->setAttribute( $key, $value );
214
+ }
 
215
 
216
+ $original_image = new PHPHtmlParser\Dom\HtmlNode( $img );
217
+ $noscript_tag = new PHPHtmlParser\Dom\Tag( 'noscript' );
218
+ $noscript = new PHPHtmlParser\Dom\HtmlNode( $noscript_tag );
219
 
220
+ /**
221
+ * Filter the LazyLoad placeholder on src attribute
222
+ *
223
+ * @since 1.1
224
+ *
225
+ * @param string $placeholder Placeholder that will be printed.
226
+ */
227
+ $placeholder = apply_filters( 'rocket_lazyload_placeholder', 'data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=' );
228
+
229
+ $image->setAttribute( 'src', $placeholder );
230
+ $image->setAttribute( 'data-lazy-src', $image_attributes['src'] );
231
 
232
+ if ( isset( $image_attributes['srcset'] ) ) {
233
+ $image->removeAttribute( 'srcset' );
234
+ $image->setAttribute( 'data-lazy-srcset', $image_attributes['srcset'] );
235
+ }
236
 
237
+ if ( isset( $image_attributes['sizes'] ) ) {
238
+ $image->removeAttribute( 'sizes' );
239
+ $image->setAttribute( 'data-lazy-sizes', $image_attributes['sizes'] );
240
+ }
241
 
242
+ $noscript->addChild( $original_image );
 
 
 
 
 
 
 
243
 
244
+ $parent = $image->getParent();
245
+ $parent->insertAfter( $noscript, $image->id() );
246
+ }
247
+
248
+ return $dom;
249
  }
250
+ add_filter( 'get_avatar' , 'rocket_lazyload_images', PHP_INT_MAX );
251
+ add_filter( 'the_content' , 'rocket_lazyload_images', PHP_INT_MAX );
252
+ add_filter( 'widget_text' , 'rocket_lazyload_images', PHP_INT_MAX );
253
+ add_filter( 'get_image_tag' , 'rocket_lazyload_images', PHP_INT_MAX );
254
+ add_filter( 'post_thumbnail_html', 'rocket_lazyload_images', PHP_INT_MAX );
255
 
256
  /**
257
  * Determine if the current image should be excluded from lazyload
258
  *
259
+ * @since 1.3 Moved check logic in the function directly
260
  * @since 1.1
261
  * @author Remy Perona
262
  *
263
+ * @param array $attributes Array containing image attributes.
 
264
  * @return bool True if one of the excluded values was found, false otherwise
265
  */
266
+ function rocket_is_excluded_lazyload( $attributes ) {
267
+ if ( function_exists( 'wr2x_picture_rewrite' ) ) {
268
+ if ( wr2x_get_retina( trailingslashit( ABSPATH ) . wr2x_get_pathinfo_from_image_src( trim( $attributes['src'], '"' ) ) ) ) {
269
  return true;
270
  }
271
  }
272
 
273
+ $excluded_attributes = apply_filters( 'rocket_lazyload_excluded_attributes', array(
274
+ 'data-no-lazy',
275
+ 'data-lazy-original',
276
+ 'data-lazy-src',
277
+ 'data-lazysrc',
278
+ 'data-lazyload',
279
+ 'data-bgposition',
280
+ 'data-envira-src',
281
+ 'fullurl',
282
+ 'lazy-slider-img',
283
+ 'data-srcset',
284
+ ) );
285
+
286
+ $excluded_classes = apply_filters( 'rocket_lazyload_excluded_classes', array(
287
+ 'ls-l',
288
+ 'ls-bg',
289
+ ) );
290
+
291
+ $excluded_src = apply_filters( 'rocket_lazyload_excluded_src', array(
292
+ '/wpcf7_captcha/',
293
+ 'timthumb.php?src',
294
+ ) );
295
+
296
+ if ( array_intersect( $attributes, $excluded_attributes, $excluded_classes, $excluded_src ) ) {
297
+ return true;
298
+ }
299
+
300
  return false;
301
  }
302
 
418
 
419
  }
420
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  /**
422
  * Replace iframes by LazyLoad
423
  *
429
  */
430
  function rocket_lazyload_iframes( $html ) {
431
  // Don't LazyLoad if process is stopped for these reasons.
432
+ if ( ! rocket_lazyload_get_option( 'iframes' ) || ! apply_filters( 'do_rocket_lazyload_iframes', true ) || is_feed() || is_preview() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || empty( $html ) || ( defined( 'DONOTLAZYLOAD' ) && DONOTLAZYLOAD ) ) {
433
  return $html;
434
  }
435
 
436
+ $dom = new PHPHtmlParser\Dom();
437
+ $dom->load( $html );
438
+ $iframes = $dom->getElementsByTag( 'iframe' );
439
+
440
+ if ( ! $iframes ) {
441
+ return $html;
442
+ }
443
 
444
+ foreach ( $iframes as $iframe ) {
445
+ $iframe_attributes = $iframe->getAttributes();
446
 
447
  // Don't mess with the Gravity Forms ajax iframe.
448
+ if ( isset( $iframe_attributes['id'] ) && false !== strpos( $iframe_attributes['id'], 'gform_ajax_frame' ) || isset( $iframe_attributes['name'] ) && false !== strpos( $iframe_attributes['name'], 'gform_ajax_frame' ) ) {
449
  continue;
450
  }
451
 
452
  // Don't lazyload if iframe has data-no-lazy attribute.
453
+ if ( isset( $iframe_attributes['data-no-lazy'] ) ) {
454
  continue;
455
  }
456
 
457
+ $iframe_tag = new PHPHtmlParser\Dom\Tag( 'iframe' );
 
 
 
 
 
 
 
458
 
459
+ foreach ( $iframe_attributes as $key => $value ) {
460
+ $iframe_tag->setAttribute( $key, $value );
461
+ }
462
 
463
+ $original_iframe = new PHPHtmlParser\Dom\HtmlNode( $iframe_tag );
464
+ $noscript_tag = new PHPHtmlParser\Dom\Tag( 'noscript' );
465
+ $noscript = new PHPHtmlParser\Dom\HtmlNode( $noscript_tag );
466
 
467
  /**
468
+ * Filter the LazyLoad placeholder on src attribute
469
  *
470
  * @since 1.1
471
  *
472
+ * @param string $placeholder placeholder that will be printed.
473
+ */
474
+ $placeholder = apply_filters( 'rocket_lazyload_placeholder', 'about:blank' );
475
+
476
+ $iframe->setAttribute( 'src', $placeholder );
477
+ $iframe->setAttribute( 'data-lazy-src', $iframe_attributes['src'] );
478
+ $iframe->setAttribute( 'data-rocket-lazyload', 'fitvidscompatible' );
479
+
480
+ $noscript->addChild( $original_iframe );
481
+
482
+ $parent = $iframe->getParent();
483
+ $parent->insertAfter( $noscript, $iframe->id() );
484
  }
485
 
486
+ return $dom;
487
  }
488
  add_filter( 'the_content', 'rocket_lazyload_iframes', PHP_INT_MAX );
489
  add_filter( 'widget_text', 'rocket_lazyload_iframes', PHP_INT_MAX );
vendor/autoload.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload.php @generated by Composer
4
+
5
+ require_once __DIR__ . '/composer/autoload_real.php';
6
+
7
+ return ComposerAutoloaderInit6b11730bf9ca7991cb734e6839a3d592::getLoader();
vendor/composer/ClassLoader.php ADDED
@@ -0,0 +1,445 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * This file is part of Composer.
5
+ *
6
+ * (c) Nils Adermann <naderman@naderman.de>
7
+ * Jordi Boggiano <j.boggiano@seld.be>
8
+ *
9
+ * For the full copyright and license information, please view the LICENSE
10
+ * file that was distributed with this source code.
11
+ */
12
+
13
+ namespace Composer\Autoload;
14
+
15
+ /**
16
+ * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17
+ *
18
+ * $loader = new \Composer\Autoload\ClassLoader();
19
+ *
20
+ * // register classes with namespaces
21
+ * $loader->add('Symfony\Component', __DIR__.'/component');
22
+ * $loader->add('Symfony', __DIR__.'/framework');
23
+ *
24
+ * // activate the autoloader
25
+ * $loader->register();
26
+ *
27
+ * // to enable searching the include path (eg. for PEAR packages)
28
+ * $loader->setUseIncludePath(true);
29
+ *
30
+ * In this example, if you try to use a class in the Symfony\Component
31
+ * namespace or one of its children (Symfony\Component\Console for instance),
32
+ * the autoloader will first look for the class under the component/
33
+ * directory, and it will then fallback to the framework/ directory if not
34
+ * found before giving up.
35
+ *
36
+ * This class is loosely based on the Symfony UniversalClassLoader.
37
+ *
38
+ * @author Fabien Potencier <fabien@symfony.com>
39
+ * @author Jordi Boggiano <j.boggiano@seld.be>
40
+ * @see http://www.php-fig.org/psr/psr-0/
41
+ * @see http://www.php-fig.org/psr/psr-4/
42
+ */
43
+ class ClassLoader
44
+ {
45
+ // PSR-4
46
+ private $prefixLengthsPsr4 = array();
47
+ private $prefixDirsPsr4 = array();
48
+ private $fallbackDirsPsr4 = array();
49
+
50
+ // PSR-0
51
+ private $prefixesPsr0 = array();
52
+ private $fallbackDirsPsr0 = array();
53
+
54
+ private $useIncludePath = false;
55
+ private $classMap = array();
56
+ private $classMapAuthoritative = false;
57
+ private $missingClasses = array();
58
+ private $apcuPrefix;
59
+
60
+ public function getPrefixes()
61
+ {
62
+ if (!empty($this->prefixesPsr0)) {
63
+ return call_user_func_array('array_merge', $this->prefixesPsr0);
64
+ }
65
+
66
+ return array();
67
+ }
68
+
69
+ public function getPrefixesPsr4()
70
+ {
71
+ return $this->prefixDirsPsr4;
72
+ }
73
+
74
+ public function getFallbackDirs()
75
+ {
76
+ return $this->fallbackDirsPsr0;
77
+ }
78
+
79
+ public function getFallbackDirsPsr4()
80
+ {
81
+ return $this->fallbackDirsPsr4;
82
+ }
83
+
84
+ public function getClassMap()
85
+ {
86
+ return $this->classMap;
87
+ }
88
+
89
+ /**
90
+ * @param array $classMap Class to filename map
91
+ */
92
+ public function addClassMap(array $classMap)
93
+ {
94
+ if ($this->classMap) {
95
+ $this->classMap = array_merge($this->classMap, $classMap);
96
+ } else {
97
+ $this->classMap = $classMap;
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Registers a set of PSR-0 directories for a given prefix, either
103
+ * appending or prepending to the ones previously set for this prefix.
104
+ *
105
+ * @param string $prefix The prefix
106
+ * @param array|string $paths The PSR-0 root directories
107
+ * @param bool $prepend Whether to prepend the directories
108
+ */
109
+ public function add($prefix, $paths, $prepend = false)
110
+ {
111
+ if (!$prefix) {
112
+ if ($prepend) {
113
+ $this->fallbackDirsPsr0 = array_merge(
114
+ (array) $paths,
115
+ $this->fallbackDirsPsr0
116
+ );
117
+ } else {
118
+ $this->fallbackDirsPsr0 = array_merge(
119
+ $this->fallbackDirsPsr0,
120
+ (array) $paths
121
+ );
122
+ }
123
+
124
+ return;
125
+ }
126
+
127
+ $first = $prefix[0];
128
+ if (!isset($this->prefixesPsr0[$first][$prefix])) {
129
+ $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130
+
131
+ return;
132
+ }
133
+ if ($prepend) {
134
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
135
+ (array) $paths,
136
+ $this->prefixesPsr0[$first][$prefix]
137
+ );
138
+ } else {
139
+ $this->prefixesPsr0[$first][$prefix] = array_merge(
140
+ $this->prefixesPsr0[$first][$prefix],
141
+ (array) $paths
142
+ );
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Registers a set of PSR-4 directories for a given namespace, either
148
+ * appending or prepending to the ones previously set for this namespace.
149
+ *
150
+ * @param string $prefix The prefix/namespace, with trailing '\\'
151
+ * @param array|string $paths The PSR-4 base directories
152
+ * @param bool $prepend Whether to prepend the directories
153
+ *
154
+ * @throws \InvalidArgumentException
155
+ */
156
+ public function addPsr4($prefix, $paths, $prepend = false)
157
+ {
158
+ if (!$prefix) {
159
+ // Register directories for the root namespace.
160
+ if ($prepend) {
161
+ $this->fallbackDirsPsr4 = array_merge(
162
+ (array) $paths,
163
+ $this->fallbackDirsPsr4
164
+ );
165
+ } else {
166
+ $this->fallbackDirsPsr4 = array_merge(
167
+ $this->fallbackDirsPsr4,
168
+ (array) $paths
169
+ );
170
+ }
171
+ } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172
+ // Register directories for a new namespace.
173
+ $length = strlen($prefix);
174
+ if ('\\' !== $prefix[$length - 1]) {
175
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176
+ }
177
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
179
+ } elseif ($prepend) {
180
+ // Prepend directories for an already registered namespace.
181
+ $this->prefixDirsPsr4[$prefix] = array_merge(
182
+ (array) $paths,
183
+ $this->prefixDirsPsr4[$prefix]
184
+ );
185
+ } else {
186
+ // Append directories for an already registered namespace.
187
+ $this->prefixDirsPsr4[$prefix] = array_merge(
188
+ $this->prefixDirsPsr4[$prefix],
189
+ (array) $paths
190
+ );
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Registers a set of PSR-0 directories for a given prefix,
196
+ * replacing any others previously set for this prefix.
197
+ *
198
+ * @param string $prefix The prefix
199
+ * @param array|string $paths The PSR-0 base directories
200
+ */
201
+ public function set($prefix, $paths)
202
+ {
203
+ if (!$prefix) {
204
+ $this->fallbackDirsPsr0 = (array) $paths;
205
+ } else {
206
+ $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Registers a set of PSR-4 directories for a given namespace,
212
+ * replacing any others previously set for this namespace.
213
+ *
214
+ * @param string $prefix The prefix/namespace, with trailing '\\'
215
+ * @param array|string $paths The PSR-4 base directories
216
+ *
217
+ * @throws \InvalidArgumentException
218
+ */
219
+ public function setPsr4($prefix, $paths)
220
+ {
221
+ if (!$prefix) {
222
+ $this->fallbackDirsPsr4 = (array) $paths;
223
+ } else {
224
+ $length = strlen($prefix);
225
+ if ('\\' !== $prefix[$length - 1]) {
226
+ throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227
+ }
228
+ $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229
+ $this->prefixDirsPsr4[$prefix] = (array) $paths;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Turns on searching the include path for class files.
235
+ *
236
+ * @param bool $useIncludePath
237
+ */
238
+ public function setUseIncludePath($useIncludePath)
239
+ {
240
+ $this->useIncludePath = $useIncludePath;
241
+ }
242
+
243
+ /**
244
+ * Can be used to check if the autoloader uses the include path to check
245
+ * for classes.
246
+ *
247
+ * @return bool
248
+ */
249
+ public function getUseIncludePath()
250
+ {
251
+ return $this->useIncludePath;
252
+ }
253
+
254
+ /**
255
+ * Turns off searching the prefix and fallback directories for classes
256
+ * that have not been registered with the class map.
257
+ *
258
+ * @param bool $classMapAuthoritative
259
+ */
260
+ public function setClassMapAuthoritative($classMapAuthoritative)
261
+ {
262
+ $this->classMapAuthoritative = $classMapAuthoritative;
263
+ }
264
+
265
+ /**
266
+ * Should class lookup fail if not found in the current class map?
267
+ *
268
+ * @return bool
269
+ */
270
+ public function isClassMapAuthoritative()
271
+ {
272
+ return $this->classMapAuthoritative;
273
+ }
274
+
275
+ /**
276
+ * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
+ *
278
+ * @param string|null $apcuPrefix
279
+ */
280
+ public function setApcuPrefix($apcuPrefix)
281
+ {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
+ }
284
+
285
+ /**
286
+ * The APCu prefix in use, or null if APCu caching is not enabled.
287
+ *
288
+ * @return string|null
289
+ */
290
+ public function getApcuPrefix()
291
+ {
292
+ return $this->apcuPrefix;
293
+ }
294
+
295
+ /**
296
+ * Registers this instance as an autoloader.
297
+ *
298
+ * @param bool $prepend Whether to prepend the autoloader or not
299
+ */
300
+ public function register($prepend = false)
301
+ {
302
+ spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303
+ }
304
+
305
+ /**
306
+ * Unregisters this instance as an autoloader.
307
+ */
308
+ public function unregister()
309
+ {
310
+ spl_autoload_unregister(array($this, 'loadClass'));
311
+ }
312
+
313
+ /**
314
+ * Loads the given class or interface.
315
+ *
316
+ * @param string $class The name of the class
317
+ * @return bool|null True if loaded, null otherwise
318
+ */
319
+ public function loadClass($class)
320
+ {
321
+ if ($file = $this->findFile($class)) {
322
+ includeFile($file);
323
+
324
+ return true;
325
+ }
326
+ }
327
+
328
+ /**
329
+ * Finds the path to the file where the class is defined.
330
+ *
331
+ * @param string $class The name of the class
332
+ *
333
+ * @return string|false The path if found, false otherwise
334
+ */
335
+ public function findFile($class)
336
+ {
337
+ // class map lookup
338
+ if (isset($this->classMap[$class])) {
339
+ return $this->classMap[$class];
340
+ }
341
+ if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
+ return false;
343
+ }
344
+ if (null !== $this->apcuPrefix) {
345
+ $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
+ if ($hit) {
347
+ return $file;
348
+ }
349
+ }
350
+
351
+ $file = $this->findFileWithExtension($class, '.php');
352
+
353
+ // Search for Hack files if we are running on HHVM
354
+ if (false === $file && defined('HHVM_VERSION')) {
355
+ $file = $this->findFileWithExtension($class, '.hh');
356
+ }
357
+
358
+ if (null !== $this->apcuPrefix) {
359
+ apcu_add($this->apcuPrefix.$class, $file);
360
+ }
361
+
362
+ if (false === $file) {
363
+ // Remember that this class does not exist.
364
+ $this->missingClasses[$class] = true;
365
+ }
366
+
367
+ return $file;
368
+ }
369
+
370
+ private function findFileWithExtension($class, $ext)
371
+ {
372
+ // PSR-4 lookup
373
+ $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374
+
375
+ $first = $class[0];
376
+ if (isset($this->prefixLengthsPsr4[$first])) {
377
+ $subPath = $class;
378
+ while (false !== $lastPos = strrpos($subPath, '\\')) {
379
+ $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath.'\\';
381
+ if (isset($this->prefixDirsPsr4[$search])) {
382
+ foreach ($this->prefixDirsPsr4[$search] as $dir) {
383
+ $length = $this->prefixLengthsPsr4[$first][$search];
384
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
385
+ return $file;
386
+ }
387
+ }
388
+ }
389
+ }
390
+ }
391
+
392
+ // PSR-4 fallback dirs
393
+ foreach ($this->fallbackDirsPsr4 as $dir) {
394
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395
+ return $file;
396
+ }
397
+ }
398
+
399
+ // PSR-0 lookup
400
+ if (false !== $pos = strrpos($class, '\\')) {
401
+ // namespaced class name
402
+ $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403
+ . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404
+ } else {
405
+ // PEAR-like class name
406
+ $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407
+ }
408
+
409
+ if (isset($this->prefixesPsr0[$first])) {
410
+ foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411
+ if (0 === strpos($class, $prefix)) {
412
+ foreach ($dirs as $dir) {
413
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414
+ return $file;
415
+ }
416
+ }
417
+ }
418
+ }
419
+ }
420
+
421
+ // PSR-0 fallback dirs
422
+ foreach ($this->fallbackDirsPsr0 as $dir) {
423
+ if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424
+ return $file;
425
+ }
426
+ }
427
+
428
+ // PSR-0 include paths.
429
+ if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430
+ return $file;
431
+ }
432
+
433
+ return false;
434
+ }
435
+ }
436
+
437
+ /**
438
+ * Scope isolated include.
439
+ *
440
+ * Prevents access to $this/self from included files.
441
+ */
442
+ function includeFile($file)
443
+ {
444
+ include $file;
445
+ }
vendor/composer/LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Copyright (c) Nils Adermann, Jordi Boggiano
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is furnished
9
+ to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ THE SOFTWARE.
21
+
vendor/composer/autoload_classmap.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_classmap.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_namespaces.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_namespaces.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ 'stringEncode' => array($vendorDir . '/paquettg/string-encode/src'),
10
+ 'PHPHtmlParser' => array($vendorDir . '/paquettg/php-html-parser/src'),
11
+ );
vendor/composer/autoload_psr4.php ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_psr4.php @generated by Composer
4
+
5
+ $vendorDir = dirname(dirname(__FILE__));
6
+ $baseDir = dirname($vendorDir);
7
+
8
+ return array(
9
+ );
vendor/composer/autoload_real.php ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_real.php @generated by Composer
4
+
5
+ class ComposerAutoloaderInit6b11730bf9ca7991cb734e6839a3d592
6
+ {
7
+ private static $loader;
8
+
9
+ public static function loadClassLoader($class)
10
+ {
11
+ if ('Composer\Autoload\ClassLoader' === $class) {
12
+ require __DIR__ . '/ClassLoader.php';
13
+ }
14
+ }
15
+
16
+ public static function getLoader()
17
+ {
18
+ if (null !== self::$loader) {
19
+ return self::$loader;
20
+ }
21
+
22
+ spl_autoload_register(array('ComposerAutoloaderInit6b11730bf9ca7991cb734e6839a3d592', 'loadClassLoader'), true, true);
23
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit6b11730bf9ca7991cb734e6839a3d592', 'loadClassLoader'));
25
+
26
+ $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
+ if ($useStaticLoader) {
28
+ require_once __DIR__ . '/autoload_static.php';
29
+
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit6b11730bf9ca7991cb734e6839a3d592::getInitializer($loader));
31
+ } else {
32
+ $map = require __DIR__ . '/autoload_namespaces.php';
33
+ foreach ($map as $namespace => $path) {
34
+ $loader->set($namespace, $path);
35
+ }
36
+
37
+ $map = require __DIR__ . '/autoload_psr4.php';
38
+ foreach ($map as $namespace => $path) {
39
+ $loader->setPsr4($namespace, $path);
40
+ }
41
+
42
+ $classMap = require __DIR__ . '/autoload_classmap.php';
43
+ if ($classMap) {
44
+ $loader->addClassMap($classMap);
45
+ }
46
+ }
47
+
48
+ $loader->register(true);
49
+
50
+ return $loader;
51
+ }
52
+ }
vendor/composer/autoload_static.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // autoload_static.php @generated by Composer
4
+
5
+ namespace Composer\Autoload;
6
+
7
+ class ComposerStaticInit6b11730bf9ca7991cb734e6839a3d592
8
+ {
9
+ public static $prefixesPsr0 = array (
10
+ 's' =>
11
+ array (
12
+ 'stringEncode' =>
13
+ array (
14
+ 0 => __DIR__ . '/..' . '/paquettg/string-encode/src',
15
+ ),
16
+ ),
17
+ 'P' =>
18
+ array (
19
+ 'PHPHtmlParser' =>
20
+ array (
21
+ 0 => __DIR__ . '/..' . '/paquettg/php-html-parser/src',
22
+ ),
23
+ ),
24
+ );
25
+
26
+ public static function getInitializer(ClassLoader $loader)
27
+ {
28
+ return \Closure::bind(function () use ($loader) {
29
+ $loader->prefixesPsr0 = ComposerStaticInit6b11730bf9ca7991cb734e6839a3d592::$prefixesPsr0;
30
+
31
+ }, null, ClassLoader::class);
32
+ }
33
+ }
vendor/composer/installed.json ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [
2
+ {
3
+ "name": "paquettg/string-encode",
4
+ "version": "0.1.1",
5
+ "version_normalized": "0.1.1.0",
6
+ "source": {
7
+ "type": "git",
8
+ "url": "https://github.com/paquettg/string-encoder.git",
9
+ "reference": "cf08343649701979f581c1601d01247fa3782439"
10
+ },
11
+ "dist": {
12
+ "type": "zip",
13
+ "url": "https://api.github.com/repos/paquettg/string-encoder/zipball/cf08343649701979f581c1601d01247fa3782439",
14
+ "reference": "cf08343649701979f581c1601d01247fa3782439",
15
+ "shasum": ""
16
+ },
17
+ "require": {
18
+ "php": ">=5.4"
19
+ },
20
+ "require-dev": {
21
+ "phpunit/phpunit": "3.7.*"
22
+ },
23
+ "time": "2014-05-29T18:38:09+00:00",
24
+ "type": "library",
25
+ "installation-source": "dist",
26
+ "autoload": {
27
+ "psr-0": {
28
+ "stringEncode": "src/"
29
+ }
30
+ },
31
+ "notification-url": "https://packagist.org/downloads/",
32
+ "license": [
33
+ "MIT"
34
+ ],
35
+ "authors": [
36
+ {
37
+ "name": "Gilles Paquette",
38
+ "email": "paquettg@gmail.com",
39
+ "homepage": "http://gillespaquette.ca"
40
+ }
41
+ ],
42
+ "description": "Facilitating the process of altering string encoding in PHP.",
43
+ "homepage": "https://github.com/paquettg/string-encoder",
44
+ "keywords": [
45
+ "charset",
46
+ "encoding",
47
+ "string"
48
+ ]
49
+ },
50
+ {
51
+ "name": "paquettg/php-html-parser",
52
+ "version": "1.7.0",
53
+ "version_normalized": "1.7.0.0",
54
+ "source": {
55
+ "type": "git",
56
+ "url": "https://github.com/paquettg/php-html-parser.git",
57
+ "reference": "18845e09831dd0772b88b51e788a4f74c701224c"
58
+ },
59
+ "dist": {
60
+ "type": "zip",
61
+ "url": "https://api.github.com/repos/paquettg/php-html-parser/zipball/18845e09831dd0772b88b51e788a4f74c701224c",
62
+ "reference": "18845e09831dd0772b88b51e788a4f74c701224c",
63
+ "shasum": ""
64
+ },
65
+ "require": {
66
+ "paquettg/string-encode": "~0.1.0",
67
+ "php": ">=5.4"
68
+ },
69
+ "require-dev": {
70
+ "mockery/mockery": "~0.9.0",
71
+ "phpunit/phpunit": "~4.8.0",
72
+ "satooshi/php-coveralls": "~0.6.0"
73
+ },
74
+ "time": "2016-04-06T15:24:40+00:00",
75
+ "type": "library",
76
+ "installation-source": "dist",
77
+ "autoload": {
78
+ "psr-0": {
79
+ "PHPHtmlParser": "src/"
80
+ }
81
+ },
82
+ "notification-url": "https://packagist.org/downloads/",
83
+ "license": [
84
+ "MIT"
85
+ ],
86
+ "authors": [
87
+ {
88
+ "name": "Gilles Paquette",
89
+ "email": "paquettg@gmail.com",
90
+ "homepage": "http://gillespaquette.ca"
91
+ }
92
+ ],
93
+ "description": "An HTML DOM parser. It allows you to manipulate HTML. Find tags on an HTML page with selectors just like jQuery.",
94
+ "homepage": "https://github.com/paquettg/php-html-parser",
95
+ "keywords": [
96
+ "dom",
97
+ "html",
98
+ "parser"
99
+ ]
100
+ }
101
+ ]
vendor/paquettg/php-html-parser/.scrutinizer.yml ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ filter:
2
+ paths: [src/*]
3
+ excluded_paths: [tests/*]
4
+ checks:
5
+ php:
6
+ code_rating: true
7
+ remove_extra_empty_lines: true
8
+ remove_php_closing_tag: true
9
+ remove_trailing_whitespace: true
10
+ fix_use_statements:
11
+ remove_unused: true
12
+ preserve_multiple: false
13
+ preserve_blanklines: true
14
+ order_alphabetically: true
15
+ fix_php_opening_tag: true
16
+ fix_linefeed: true
17
+ fix_line_ending: true
18
+ fix_identation_4spaces: true
19
+ fix_doc_comments: true
20
+ tools:
21
+ external_code_coverage:
22
+ timeout: 600
23
+ runs: 3
24
+ php_code_coverage: false
25
+ php_code_sniffer:
26
+ config:
27
+ standard: PSR2
28
+ filter:
29
+ paths: ['src']
30
+ php_loc:
31
+ enabled: true
32
+ excluded_dirs: [vendor, test]
33
+ php_cpd:
34
+ enabled: true
35
+ excluded_dirs: [vendor, test]
vendor/paquettg/php-html-parser/.travis.yml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - 5.6
7
+ - 7.0
8
+ - hhvm
9
+
10
+ install:
11
+ - composer self-update
12
+ - composer install --dev --no-interaction
13
+
14
+ script:
15
+ - mkdir -p build/logs
16
+ - php vendor/bin/phpunit --coverage-clover build/logs/clover.xml
17
+
18
+ after_script:
19
+ - php vendor/bin/coveralls
vendor/paquettg/php-html-parser/CHANGELOG.md ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Development
2
+
3
+ ## 1.7.0
4
+
5
+ - Added .scrutinizer.yml to repo
6
+ - Reformated code to PSR-1/2
7
+ - Improved the test coverage and some small code changes
8
+ - Added removeAttribute and removeAllAttributes tag methods fixes #57
9
+ - Added replaceNode method implements #52
10
+ - Added a delete method. fixes #43
11
+ - Added semicolon after &#10 for linebreak preservation. fixes #62
12
+ - Removed code that removed <code> tag fixes #60
13
+ - Added new test related to #63
14
+ - Refactored the nodes into inner and leaf nodes
15
+ - Fixed Strings example in README
16
+ - Close this header so the markdown will render properly
17
+ - Added preserve line break option. Defaults to false.
18
+
19
+
20
+ ## 1.6.9
21
+
22
+ - Added Changelog
23
+ - Fixed issue with spaces befor closing tag Fixes #45
24
+ - Fixed some code quality issues found by scrutinizer
25
+ - Added Scrutinizer to README
26
+ - Reformated code to comply with PSR-1/2
27
+ - Added preserve line break option. Defaults to false. fixes #40
28
+ - Updated the tests
29
+ - Added options: cleanupInput, removeScripts and removeStyles
30
+
31
+ ## 1.6.8
32
+
33
+ - Added comments and reformated some code
34
+ - Added support for non-escaped quotes in attribute value fixes #37
35
+ - Cleaned up the comments and php docs
36
+ - Removed version in composer json
37
+ - Updated composer version
38
+ - Refactoring out isChild method.
39
+ - Updated in code documentation
40
+ - Updated composer
41
+
42
+ $$ 1.6.7
43
+
44
+ - Added tests for the new array access
45
+ - Added feature to allow array usage of html node. fixes #26
46
+ - Update HtmlNode.php
47
+ - Added test to cover issue #28
48
+ - FIX: File name is longer than the maximum allowed path
49
+
50
+ ## 1.6.6
51
+
52
+ - Replaced preg_replace with mb_ereg_replace
53
+ - Added child selector fixes #24
54
+ - Updated the dev version of phpunit
55
+
56
+ ## 1.6.5
57
+
58
+ - Fixed bug when no attribute tags are last tag (with out space). fixes #16
59
+ - Fixed some documentation inconsistencies fixes #15
60
+ - Made loadStr a public methor Fixes #18
61
+ - Update a problem with the README fixes #11
62
+ - Added setAttribute to the node fixes #7
63
+ - Check if open_basedir is enabled: Dont use CURLOPT_FOLLOWLOCATION
64
+
65
+ ## 1.6.4
66
+
67
+ - Added tests and updated README
68
+ - Updated the tests and moved some files
69
+ - Added the option to enforce the encoding
70
+ - Fixed a problem with handeling the unknown child exception
71
+ - Updated some tests
72
+ - Added coverall badge and package
73
+
74
+ ## 1.6.3
75
+
76
+ - Added initial support for 'strict' parsing option
77
+ - Added an optional paramter to enable recursive text
78
+ - Added appropriat Options tests
79
+ - Changed all exception to specific objects
80
+ - Added a whitespaceTextNode option and test
81
+ - Added support for an options array
82
+
83
+ ## 1.6.2
84
+
85
+ - Standardised indentation for easyer reading on github
86
+ - Update AbstractNode.php
87
+ - Added a test for hhvm in my travis.yml
88
+ - Added a LICENSE.md file for MIT
89
+ - Added build status to README
90
+ - Added travis.yml
91
+ - Changed the file name of the abstract node
92
+ - fixed code in collection class where instance of arrayIterator is to be rturned
93
+ - Updated documentation
94
+ - Added a curl interface and a simple curl class.
95
+ - Removed the Guzzle dependancy
96
+ - Abstracted the Node class as it should have been done in the first place
97
+ - Added integrity checks for the cached html
98
+ - Added some basic caching of the dom html
99
+ - Added a toArray() method to the collection and a test
100
+
101
+ ## 1.6.1
102
+
103
+ - Moved back to using guzzle so expections are thrown when their was an error with loading a url
104
+ - Added tests for the Static Facade Fixed a few issues brought to light from the new tests
105
+ - Added a static facade
106
+ - Changed encoding to be a local attribute instead of a static attribute
107
+ - Solved issue #2 When you attempt to load an html page from a URL using loadFromUrl the encoding is incorrect.
108
+ - Added easyer loading of files and urls. Still have a problem with encoding while loading from url.
109
+ - Added guzzle and loadFromUrl option
110
+ - Fixed an issue with no value attributes
111
+ - Added magic and each methods to the collection. Plus some tests
112
+ - Added a collection object
113
+ - Added charset encoding
114
+ - fixed a bug with closing tags If a closing tag did not have an opening tag it would cause the scan to end instead of ignoring the closing tag.
vendor/paquettg/php-html-parser/CONTRIBUTING.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PHPHtmlParser Contribution Guide
2
+
3
+ This page contains guidelines for contributing to the PHPHtmlParser package. Please review these guidelines before submitting any puLl requests to the package.
4
+
5
+ ## Pull Requests
6
+
7
+ The pull request process differs for new features and bugs. Before sending a pull request for a new feature, you should first create an issue with `[Proposal]` in the title. The proposal should describe the new feature, as well as implementation ideas. The proposal will then be reviewed and either approved or denied. Once a proposal is approved, a pull request may be created implementing the new feature. Pull requests which do not follow this guideline will be closed immediately.
8
+
9
+ Pull requests for bugs may be sent without creating any proposal issue. If you believe that you know of a solution for a bug that has been filed on Github, please leave a comment detailing your proposed fix.
10
+
11
+ ### Feature Requests
12
+
13
+ If you have an idea for a new feature you would like to see added to the package, you may create an issue on Github with `[Request]` in the title. The feature request will then be reviewed.
14
+
15
+ ## Coding Guidelines
16
+
17
+ We follow the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) autoloading standard and take heavily from the [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) coding standards. In addition to these standards, below is a list of other coding standards that should be followed:
18
+
19
+ - Class opening `{` should be on the same line as the class name.
20
+ - Function and control structure opening `{` should be on a separate line.
21
+ - Interface names are suffixed with `Interface` (`FooInterface`)
vendor/paquettg/php-html-parser/LICENSE.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Gilles Paquette
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
vendor/paquettg/php-html-parser/README.md ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ PHP Html Parser
2
+ ==========================
3
+
4
+ Version 1.7.0
5
+
6
+ [![Build Status](https://travis-ci.org/paquettg/php-html-parser.png)](https://travis-ci.org/paquettg/php-html-parser)
7
+ [![Coverage Status](https://coveralls.io/repos/paquettg/php-html-parser/badge.png)](https://coveralls.io/r/paquettg/php-html-parser)
8
+ [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/paquettg/php-html-parser/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/paquettg/php-html-parser/?branch=master)
9
+
10
+ PHPHtmlParser is a simple, flexible, html parser which allows you to select tags using any css selector, like jQuery. The goal is to assiste in the development of tools which require a quick, easy way to scrap html, whether it's valid or not! This project was original supported by [sunra/php-simple-html-dom-parser](https://github.com/sunra/php-simple-html-dom-parser) but the support seems to have stopped so this project is my adaptation of his previous work.
11
+
12
+ Install
13
+ -------
14
+
15
+ This package can be found on [packagist](https://packagist.org/packages/paquettg/php-html-parser) and is best loaded using [composer](http://getcomposer.org/). We support php 5.4, 5.5, and hhvm 2.3.
16
+
17
+ Usage
18
+ -----
19
+
20
+ You can find many examples of how to use the dom parser and any of its parts (which you will most likely never touch) in the tests directory. The tests are done using PHPUnit and are very small, a few lines each, and are a great place to start. Given that, I'll still be showing a few examples of how the package should be used. The following example is a very simplistic usage of the package.
21
+
22
+ ```php
23
+ // Assuming you installed from Composer:
24
+ require "vendor/autoload.php";
25
+ use PHPHtmlParser\Dom;
26
+
27
+ $dom = new Dom;
28
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
29
+ $a = $dom->find('a')[0];
30
+ echo $a->text; // "click here"
31
+ ```
32
+
33
+ The above will output "click here". Simple no? There are many ways to get the same result from the dome, such as `$dom->getElementsbyTag('a')[0]` or `$dom->find('a', 0)` which can all be found in the tests or in the code itself.
34
+
35
+ Loading Files
36
+ ------------------
37
+
38
+ You may also seamlessly load a file into the dom instead of a string, which is much more convinient and is how I except most developers will be loading the html. The following example is taken from our test and uses the "big.html" file found there.
39
+
40
+ ```php
41
+ // Assuming you installed from Composer:
42
+ require "vendor/autoload.php";
43
+ use PHPHtmlParser\Dom;
44
+
45
+ $dom = new Dom;
46
+ $dom->loadFromFile('tests/big.html');
47
+ $contents = $dom->find('.content-border');
48
+ echo count($contents); // 10
49
+
50
+ foreach ($contents as $content)
51
+ {
52
+ // get the class attr
53
+ $class = $content->getAttribute('class');
54
+
55
+ // do something with the html
56
+ $html = $content->innerHtml;
57
+
58
+ // or refine the find some more
59
+ $child = $content->firstChild();
60
+ $sibling = $child->nextSibling();
61
+ }
62
+ ```
63
+
64
+ This example loads the html from big.html, a real page found online, and gets all the content-border classes to process. It also shows a few things you can do with a node but it is not an exhaustive list of methods that a node has avaiable.
65
+
66
+ Alternativly, you can always use the `load()` method to load the file. It will attempt to find the file using `file_exists` and, if succesfull, will call `loadFromFile()` for you. The same applies to a URL and `loadFromUrl()` method.
67
+
68
+ Loading Url
69
+ ----------------
70
+
71
+ Loading a url is very similar to the way you would load the html from a file.
72
+
73
+ ```php
74
+ // Assuming you installed from Composer:
75
+ require "vendor/autoload.php";
76
+ use PHPHtmlParser\Dom;
77
+
78
+ $dom = new Dom;
79
+ $dom->loadFromUrl('http://google.com');
80
+ $html = $dom->outerHtml;
81
+
82
+ // or
83
+ $dom->load('http://google.com');
84
+ $html = $dom->outerHtml; // same result as the first example
85
+ ```
86
+
87
+ What makes the loadFromUrl method note worthy is the `PHPHtmlParser\CurlInterface` parameter, an optional second parameter. By default, we use the `PHPHtmlParser\Curl` class to get the contents of the url. On the other hand, though, you can inject your own implementation of CurlInterface and we will attempt to load the url using what ever tool/settings you want, up to you.
88
+
89
+ ```php
90
+ // Assuming you installed from Composer:
91
+ require "vendor/autoload.php";
92
+ use PHPHtmlParser\Dom;
93
+ use App\Services\Connector;
94
+
95
+ $dom = new Dom;
96
+ $dom->loadFromUrl('http://google.com', [], new Connector);
97
+ $html = $dom->outerHtml;
98
+ ```
99
+
100
+ As long as the Connector object implements the `PHPHtmlParser\CurlInterface` interface properly it will use that object to get the content of the url instead of the default `PHPHtmlParser\Curl` class.
101
+
102
+ Loading Strings
103
+ ---------------
104
+
105
+ Loading a string directly, with out the checks in `load()` is also easely done.
106
+
107
+ ```php
108
+ // Assuming you installed from Composer:
109
+ require "vendor/autoload.php";
110
+ use PHPHtmlParser\Dom;
111
+
112
+ $dom = new Dom;
113
+ $dom->loadStr('<html>String</html>', []);
114
+ $html = $dom->outerHtml;
115
+ ```
116
+
117
+ If the string is to long, depending on your file system, the `load()` method will throw a warning. If this happens you can just call the above method to bypass the `is_file()` check in the `load()` method.
118
+
119
+ Options
120
+ -------
121
+
122
+ You can also set parsing option that will effect the behavior of the parsing engine. You can set a global option array using the `setOptions` method in the `Dom` object or a instance specific option by adding it to the `load` method as an extra (optional) parameter.
123
+
124
+ ```php
125
+ // Assuming you installed from Composer:
126
+ require "vendor/autoload.php";
127
+ use PHPHtmlParser\Dom;
128
+
129
+ $dom = new Dom;
130
+ $dom->setOptions([
131
+ 'strict' => true, // Set a global option to enable strict html parsing.
132
+ ]);
133
+
134
+ $dom->load('http://google.com', [
135
+ 'whitespaceTextNode' => false, // Only applies to this load.
136
+ ]);
137
+
138
+ $dom->load('http://gmail.com'); // will not have whitespaceTextNode set to false.
139
+ ```
140
+
141
+ At the moment we support 7 options.
142
+
143
+ **Strict**
144
+
145
+ Strict, by default false, will throw a `StrickException` if it find that the html is not strict complient (all tags must have a clossing tag, no attribute with out a value, etc.).
146
+
147
+ **whitespaceTextNode**
148
+
149
+ The whitespaceTextNode, by default true, option tells the parser to save textnodes even if the content of the node is empty (only whitespace). Setting it to false will ignore all whitespace only text node found in the document.
150
+
151
+ **enforceEncoding**
152
+
153
+ The enforceEncoding, by default null, option will enforce an charater set to be used for reading the content and returning the content in that encoding. Setting it to null will trigger an attempt to figure out the encoding from within the content of the string given instead.
154
+
155
+ **cleanupInput**
156
+
157
+ Set this to `true` to skip the entire clean up phase of the parser. If this is set to true the next 3 options will be ignored. Defaults to `false`.
158
+
159
+ **removeScripts**
160
+
161
+ Set this to `false` to skip removing the script tags from the document body. This might have adverse effects. Defaults to `true`.
162
+
163
+ **removeStyles**
164
+
165
+ Set this to `false` to skip removing of style tags from the document body. This might have adverse effects. Defaults to `true`.
166
+
167
+ **preserveLineBreaks**
168
+
169
+ Preserves Line Breaks if set to `true`. If set to `false` line breaks are cleaned up as part of the input clean up process. Defaults to `false`.
170
+
171
+ Static Facade
172
+ -------------
173
+
174
+ You can also mount a static facade for the Dom object.
175
+
176
+ ```PHP
177
+ PHPHtmlParser\StaticDom::mount();
178
+
179
+ Dom::load('tests/big.hmtl');
180
+ $objects = Dom::find('.content-border');
181
+
182
+ ```
183
+
184
+ The above php block does the same find and load as the first example but it is done using the static facade, which supports all public methods found in the Dom object.
185
+
186
+ Modifying The Dom
187
+ -----------------
188
+
189
+ You can always modify the dom that was created from any loading method. To change the attribute of any node you can just call the `setAttribute` method.
190
+
191
+ ```php
192
+ $dom = new Dom;
193
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
194
+ $a = $dom->find('a')[0];
195
+ $a->setAttribute('class', 'foo');
196
+ echo $a->getAttribute('class'); // "foo"
197
+ ```
198
+
199
+ You may also get the `PHPHtmlParser\Dom\Tag` class directly and manipulate it as you see fit.
200
+
201
+ ```php
202
+ $dom = new Dom;
203
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
204
+ $a = $dom->find('a')[0];
205
+ $tag = $a->getTag();
206
+ $tag->setAttribute('class', 'foo');
207
+ echo $a->getAttribute('class'); // "foo"
208
+ ```
209
+
210
+ It is also possible to remove a node from the tree. Simply call the `delete` method on any node to remove it from the tree. It is important to note that you should unset the node after removing it from the `DOM``, it will still take memory as long as it is not unset.
211
+
212
+ ```php
213
+ $dom = new Dom;
214
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
215
+ $a = $dom->find('a')[0];
216
+ $a->delete();
217
+ unset($a);
218
+ echo $dom; // '<div class="all"><p>Hey bro, <br /> :)</p></div>');
219
+ ```
vendor/paquettg/php-html-parser/composer.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "paquettg/php-html-parser",
3
+ "type": "library",
4
+ "version": "1.7.0",
5
+ "description": "An HTML DOM parser. It allows you to manipulate HTML. Find tags on an HTML page with selectors just like jQuery.",
6
+ "keywords": ["html", "dom", "parser"],
7
+ "homepage": "https://github.com/paquettg/php-html-parser",
8
+ "license": "MIT",
9
+ "authors": [
10
+ {
11
+ "name": "Gilles Paquette",
12
+ "email": "paquettg@gmail.com",
13
+ "homepage": "http://gillespaquette.ca"
14
+ }
15
+ ],
16
+ "require": {
17
+ "php": ">=5.4",
18
+ "paquettg/string-encode": "~0.1.0"
19
+ },
20
+ "require-dev": {
21
+ "phpunit/phpunit": "~4.8.0",
22
+ "satooshi/php-coveralls": "~0.6.0",
23
+ "mockery/mockery": "~0.9.0"
24
+ },
25
+ "autoload": {
26
+ "psr-0": {
27
+ "PHPHtmlParser": "src/"
28
+ }
29
+ },
30
+ "minimum-stability": "dev",
31
+ "prefer-stable": true
32
+ }
vendor/paquettg/php-html-parser/phpunit.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ |--------------------------------------------------------------------------
5
+ | Register The Composer Auto Loader
6
+ |--------------------------------------------------------------------------
7
+ |
8
+ | Composer provides a convenient, automatically generated class loader
9
+ | for our application. We just need to utilize it! We'll require it
10
+ | into the script here so that we do not have to worry about the
11
+ | loading of any our classes "manually". Feels great to relax.
12
+ |
13
+ */
14
+
15
+ require __DIR__.'/vendor/autoload.php';
16
+
17
+ /*
18
+ |--------------------------------------------------------------------------
19
+ | Set The Default Timezone
20
+ |--------------------------------------------------------------------------
21
+ |
22
+ | Here we will set the default timezone for PHP. PHP is notoriously mean
23
+ | if the timezone is not explicitly set. This will be used by each of
24
+ | the PHP date and date-time functions throughout the application.
25
+ |
26
+ */
27
+
28
+ date_default_timezone_set('UTC');
vendor/paquettg/php-html-parser/phpunit.xml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit backupGlobals="false"
3
+ backupStaticAttributes="false"
4
+ bootstrap="phpunit.php"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="false"
12
+ >
13
+ <testsuites>
14
+ <testsuite name="Repository Test Suite">
15
+ <directory>./tests/</directory>
16
+ </testsuite>
17
+ </testsuites>
18
+
19
+ <filter>
20
+ <whitelist addUncoveredFilesFromWhitelist="false">
21
+ <directory suffix=".php">src</directory>
22
+ <exclude>
23
+ <directory suffix=".php">vendor</directory>
24
+ </exclude>
25
+ </whitelist>
26
+ </filter>
27
+ </phpunit>
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Content.php ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ /**
5
+ * Class Content
6
+ *
7
+ * @package PHPHtmlParser
8
+ */
9
+ class Content
10
+ {
11
+
12
+ /**
13
+ * The content string.
14
+ *
15
+ * @var string
16
+ */
17
+ protected $content;
18
+
19
+ /**
20
+ * The size of the content.
21
+ *
22
+ * @var integer
23
+ */
24
+ protected $size;
25
+
26
+ /**
27
+ * The current position we are in the content.
28
+ *
29
+ * @var integer
30
+ */
31
+ protected $pos;
32
+
33
+ /**
34
+ * The following 4 strings are tags that are important to us.
35
+ *
36
+ * @var string
37
+ */
38
+ protected $blank = " \t\r\n";
39
+ protected $equal = ' =/>';
40
+ protected $slash = " />\r\n\t";
41
+ protected $attr = ' >';
42
+
43
+ /**
44
+ * Content constructor.
45
+ *
46
+ * @param $content
47
+ */
48
+ public function __construct($content)
49
+ {
50
+ $this->content = $content;
51
+ $this->size = strlen($content);
52
+ $this->pos = 0;
53
+ }
54
+
55
+ /**
56
+ * Returns the current position of the content.
57
+ *
58
+ * @return int
59
+ */
60
+ public function getPosition()
61
+ {
62
+ return $this->pos;
63
+ }
64
+
65
+ /**
66
+ * Gets the current character we are at.
67
+ *
68
+ * @param int $char
69
+ * @return string
70
+ */
71
+ public function char($char = null)
72
+ {
73
+ $pos = $this->pos;
74
+ if ( ! is_null($char)) {
75
+ $pos = $char;
76
+ }
77
+
78
+ if ( ! isset($this->content[$pos])) {
79
+ return '';
80
+ }
81
+
82
+ return $this->content[$pos];
83
+ }
84
+
85
+ /**
86
+ * Moves the current position forward.
87
+ *
88
+ * @param int $count
89
+ * @return $this
90
+ */
91
+ public function fastForward($count)
92
+ {
93
+ $this->pos += $count;
94
+
95
+ return $this;
96
+ }
97
+
98
+ /**
99
+ * Moves the current position backward.
100
+ *
101
+ * @param int $count
102
+ * @return $this
103
+ */
104
+ public function rewind($count)
105
+ {
106
+ $this->pos -= $count;
107
+ if ($this->pos < 0) {
108
+ $this->pos = 0;
109
+ }
110
+
111
+ return $this;
112
+ }
113
+
114
+ /**
115
+ * Copy the content until we find the given string.
116
+ *
117
+ * @param string $string
118
+ * @param bool $char
119
+ * @param bool $escape
120
+ * @return string
121
+ */
122
+ public function copyUntil($string, $char = false, $escape = false)
123
+ {
124
+ if ($this->pos >= $this->size) {
125
+ // nothing left
126
+ return '';
127
+ }
128
+
129
+ if ($escape) {
130
+ $position = $this->pos;
131
+ $found = false;
132
+ while ( ! $found) {
133
+ $position = strpos($this->content, $string, $position);
134
+ if ($position === false) {
135
+ // reached the end
136
+ $found = true;
137
+ continue;
138
+ }
139
+
140
+ if ($this->char($position - 1) == '\\') {
141
+ // this character is escaped
142
+ ++$position;
143
+ continue;
144
+ }
145
+
146
+ $found = true;
147
+ }
148
+ } elseif ($char) {
149
+ $position = strcspn($this->content, $string, $this->pos);
150
+ $position += $this->pos;
151
+ } else {
152
+ $position = strpos($this->content, $string, $this->pos);
153
+ }
154
+
155
+ if ($position === false) {
156
+ // could not find character, just return the remaining of the content
157
+ $return = substr($this->content, $this->pos, $this->size - $this->pos);
158
+ $this->pos = $this->size;
159
+
160
+ return $return;
161
+ }
162
+
163
+ if ($position == $this->pos) {
164
+ // we are at the right place
165
+ return '';
166
+ }
167
+
168
+ $return = substr($this->content, $this->pos, $position - $this->pos);
169
+ // set the new position
170
+ $this->pos = $position;
171
+
172
+ return $return;
173
+ }
174
+
175
+ /**
176
+ * Copies the content until the string is found and return it
177
+ * unless the 'unless' is found in the substring.
178
+ *
179
+ * @param string $string
180
+ * @param string $unless
181
+ * @return string
182
+ */
183
+ public function copyUntilUnless($string, $unless)
184
+ {
185
+ $lastPos = $this->pos;
186
+ $this->fastForward(1);
187
+ $foundString = $this->copyUntil($string, true, true);
188
+
189
+ $position = strcspn($foundString, $unless);
190
+ if ($position == strlen($foundString)) {
191
+ return $string.$foundString;
192
+ }
193
+ // rewind changes and return nothing
194
+ $this->pos = $lastPos;
195
+
196
+ return '';
197
+ }
198
+
199
+ /**
200
+ * Copies the content until it reaches the token string.,
201
+ *
202
+ * @param string $token
203
+ * @param bool $char
204
+ * @param bool $escape
205
+ * @return string
206
+ * @uses $this->copyUntil()
207
+ */
208
+ public function copyByToken($token, $char = false, $escape = false)
209
+ {
210
+ $string = $this->$token;
211
+
212
+ return $this->copyUntil($string, $char, $escape);
213
+ }
214
+
215
+ /**
216
+ * Skip a given set of characters.
217
+ *
218
+ * @param string $string
219
+ * @param bool $copy
220
+ * @return $this|string
221
+ */
222
+ public function skip($string, $copy = false)
223
+ {
224
+ $len = strspn($this->content, $string, $this->pos);
225
+
226
+ // make it chainable if they don't want a copy
227
+ $return = $this;
228
+ if ($copy) {
229
+ $return = substr($this->content, $this->pos, $len);
230
+ }
231
+
232
+ // update the position
233
+ $this->pos += $len;
234
+
235
+ return $return;
236
+ }
237
+
238
+ /**
239
+ * Skip a given token of pre-defined characters.
240
+ *
241
+ * @param string $token
242
+ * @param bool $copy
243
+ * @return null|string
244
+ * @uses $this->skip()
245
+ */
246
+ public function skipByToken($token, $copy = false)
247
+ {
248
+ $string = $this->$token;
249
+
250
+ return $this->skip($string, $copy);
251
+ }
252
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Curl.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ use PHPHtmlParser\Exceptions\CurlException;
5
+
6
+ /**
7
+ * Class Curl
8
+ *
9
+ * @package PHPHtmlParser
10
+ */
11
+ class Curl implements CurlInterface
12
+ {
13
+
14
+ /**
15
+ * A simple curl implementation to get the content of the url.
16
+ *
17
+ * @param string $url
18
+ * @return string
19
+ * @throws CurlException
20
+ */
21
+ public function get($url)
22
+ {
23
+ $ch = curl_init($url);
24
+
25
+ if ( ! ini_get('open_basedir')) {
26
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
27
+ }
28
+
29
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
30
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
31
+
32
+ $content = curl_exec($ch);
33
+ if ($content === false) {
34
+ // there was a problem
35
+ $error = curl_error($ch);
36
+ throw new CurlException('Error retrieving "'.$url.'" ('.$error.')');
37
+ }
38
+
39
+ return $content;
40
+ }
41
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/CurlInterface.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ /**
5
+ * Interface CurlInterface
6
+ *
7
+ * @package PHPHtmlParser
8
+ */
9
+ interface CurlInterface
10
+ {
11
+
12
+ /**
13
+ * This method should return the content of the url in a string
14
+ *
15
+ * @param string $url
16
+ * @return string
17
+ */
18
+ public function get($url);
19
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom.php ADDED
@@ -0,0 +1,648 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ use PHPHtmlParser\Dom\AbstractNode;
5
+ use PHPHtmlParser\Dom\HtmlNode;
6
+ use PHPHtmlParser\Dom\TextNode;
7
+ use PHPHtmlParser\Exceptions\NotLoadedException;
8
+ use PHPHtmlParser\Exceptions\StrictException;
9
+ use stringEncode\Encode;
10
+
11
+ /**
12
+ * Class Dom
13
+ *
14
+ * @package PHPHtmlParser
15
+ */
16
+ class Dom
17
+ {
18
+
19
+ /**
20
+ * The charset we would like the output to be in.
21
+ *
22
+ * @var string
23
+ */
24
+ protected $defaultCharset = 'UTF-8';
25
+
26
+ /**
27
+ * Contains the root node of this dom tree.
28
+ *
29
+ * @var HtmlNode
30
+ */
31
+ public $root;
32
+
33
+ /**
34
+ * The raw version of the document string.
35
+ *
36
+ * @var string
37
+ */
38
+ protected $raw;
39
+
40
+ /**
41
+ * The document string.
42
+ *
43
+ * @var Content
44
+ */
45
+ protected $content = null;
46
+
47
+ /**
48
+ * The original file size of the document.
49
+ *
50
+ * @var int
51
+ */
52
+ protected $rawSize;
53
+
54
+ /**
55
+ * The size of the document after it is cleaned.
56
+ *
57
+ * @var int
58
+ */
59
+ protected $size;
60
+
61
+ /**
62
+ * A global options array to be used by all load calls.
63
+ *
64
+ * @var array
65
+ */
66
+ protected $globalOptions = [];
67
+
68
+ /**
69
+ * A persistent option object to be used for all options in the
70
+ * parsing of the file.
71
+ *
72
+ * @var Options
73
+ */
74
+ protected $options;
75
+
76
+ /**
77
+ * A list of tags which will always be self closing
78
+ *
79
+ * @var array
80
+ */
81
+ protected $selfClosing = [
82
+ 'img',
83
+ 'br',
84
+ 'input',
85
+ 'meta',
86
+ 'link',
87
+ 'hr',
88
+ 'base',
89
+ 'embed',
90
+ 'spacer',
91
+ ];
92
+
93
+ /**
94
+ * Returns the inner html of the root node.
95
+ *
96
+ * @return string
97
+ */
98
+ public function __toString()
99
+ {
100
+ return $this->root->innerHtml();
101
+ }
102
+
103
+ /**
104
+ * A simple wrapper around the root node.
105
+ *
106
+ * @param string $name
107
+ * @return mixed
108
+ */
109
+ public function __get($name)
110
+ {
111
+ return $this->root->$name;
112
+ }
113
+
114
+ /**
115
+ * Attempts to load the dom from any resource, string, file, or URL.
116
+ *
117
+ * @param string $str
118
+ * @param array $options
119
+ * @return $this
120
+ */
121
+ public function load($str, $options = [])
122
+ {
123
+ // check if it's a file
124
+ if (strpos($str, "\n") === false && is_file($str)) {
125
+ return $this->loadFromFile($str, $options);
126
+ }
127
+ // check if it's a url
128
+ if (preg_match("/^https?:\/\//i", $str)) {
129
+ return $this->loadFromUrl($str, $options);
130
+ }
131
+
132
+ return $this->loadStr($str, $options);
133
+ }
134
+
135
+ /**
136
+ * Loads the dom from a document file/url
137
+ *
138
+ * @param string $file
139
+ * @param array $options
140
+ * @return $this
141
+ */
142
+ public function loadFromFile($file, $options = [])
143
+ {
144
+ return $this->loadStr(file_get_contents($file), $options);
145
+ }
146
+
147
+ /**
148
+ * Use a curl interface implementation to attempt to load
149
+ * the content from a url.
150
+ *
151
+ * @param string $url
152
+ * @param array $options
153
+ * @param CurlInterface $curl
154
+ * @return $this
155
+ */
156
+ public function loadFromUrl($url, $options = [], CurlInterface $curl = null)
157
+ {
158
+ if (is_null($curl)) {
159
+ // use the default curl interface
160
+ $curl = new Curl;
161
+ }
162
+ $content = $curl->get($url);
163
+
164
+ return $this->loadStr($content, $options);
165
+ }
166
+
167
+ /**
168
+ * Parsers the html of the given string. Used for load(), loadFromFile(),
169
+ * and loadFromUrl().
170
+ *
171
+ * @param string $str
172
+ * @param array $option
173
+ * @return $this
174
+ */
175
+ public function loadStr($str, $option)
176
+ {
177
+ $this->options = new Options;
178
+ $this->options->setOptions($this->globalOptions)
179
+ ->setOptions($option);
180
+
181
+ $this->rawSize = strlen($str);
182
+ $this->raw = $str;
183
+
184
+ $html = $this->clean($str);
185
+
186
+ $this->size = strlen($str);
187
+ $this->content = new Content($html);
188
+
189
+ $this->parse();
190
+ $this->detectCharset();
191
+
192
+ return $this;
193
+ }
194
+
195
+ /**
196
+ * Sets a global options array to be used by all load calls.
197
+ *
198
+ * @param array $options
199
+ * @return $this
200
+ */
201
+ public function setOptions(array $options)
202
+ {
203
+ $this->globalOptions = $options;
204
+
205
+ return $this;
206
+ }
207
+
208
+ /**
209
+ * Find elements by css selector on the root node.
210
+ *
211
+ * @param string $selector
212
+ * @param int $nth
213
+ * @return array
214
+ */
215
+ public function find($selector, $nth = null)
216
+ {
217
+ $this->isLoaded();
218
+
219
+ return $this->root->find($selector, $nth);
220
+ }
221
+
222
+ /**
223
+ * Adds the tag (or tags in an array) to the list of tags that will always
224
+ * be self closing.
225
+ *
226
+ * @param string|array $tag
227
+ * @return $this
228
+ */
229
+ public function addSelfClosingTag($tag)
230
+ {
231
+ if ( ! is_array($tag)) {
232
+ $tag = [$tag];
233
+ }
234
+ foreach ($tag as $value) {
235
+ $this->selfClosing[] = $value;
236
+ }
237
+
238
+ return $this;
239
+ }
240
+
241
+ /**
242
+ * Removes the tag (or tags in an array) from the list of tags that will
243
+ * always be self closing.
244
+ *
245
+ * @param string|array $tag
246
+ * @return $this
247
+ */
248
+ public function removeSelfClosingTag($tag)
249
+ {
250
+ if ( ! is_array($tag)) {
251
+ $tag = [$tag];
252
+ }
253
+ $this->selfClosing = array_diff($this->selfClosing, $tag);
254
+
255
+ return $this;
256
+ }
257
+
258
+ /**
259
+ * Sets the list of self closing tags to empty.
260
+ *
261
+ * @return $this
262
+ */
263
+ public function clearSelfClosingTags()
264
+ {
265
+ $this->selfClosing = [];
266
+
267
+ return $this;
268
+ }
269
+
270
+ /**
271
+ * Simple wrapper function that returns the first child.
272
+ *
273
+ * @return \PHPHtmlParser\Dom\AbstractNode
274
+ */
275
+ public function firstChild()
276
+ {
277
+ $this->isLoaded();
278
+
279
+ return $this->root->firstChild();
280
+ }
281
+
282
+ /**
283
+ * Simple wrapper function that returns the last child.
284
+ *
285
+ * @return \PHPHtmlParser\Dom\AbstractNode
286
+ */
287
+ public function lastChild()
288
+ {
289
+ $this->isLoaded();
290
+
291
+ return $this->root->lastChild();
292
+ }
293
+
294
+ /**
295
+ * Simple wrapper function that returns an element by the
296
+ * id.
297
+ *
298
+ * @param string $id
299
+ * @return \PHPHtmlParser\Dom\AbstractNode
300
+ */
301
+ public function getElementById($id)
302
+ {
303
+ $this->isLoaded();
304
+
305
+ return $this->find('#'.$id, 0);
306
+ }
307
+
308
+ /**
309
+ * Simple wrapper function that returns all elements by
310
+ * tag name.
311
+ *
312
+ * @param string $name
313
+ * @return array
314
+ */
315
+ public function getElementsByTag($name)
316
+ {
317
+ $this->isLoaded();
318
+
319
+ return $this->find($name);
320
+ }
321
+
322
+ /**
323
+ * Simple wrapper function that returns all elements by
324
+ * class name.
325
+ *
326
+ * @param string $class
327
+ * @return array
328
+ */
329
+ public function getElementsByClass($class)
330
+ {
331
+ $this->isLoaded();
332
+
333
+ return $this->find('.'.$class);
334
+ }
335
+
336
+ /**
337
+ * Checks if the load methods have been called.
338
+ *
339
+ * @throws NotLoadedException
340
+ */
341
+ protected function isLoaded()
342
+ {
343
+ if (is_null($this->content)) {
344
+ throw new NotLoadedException('Content is not loaded!');
345
+ }
346
+ }
347
+
348
+ /**
349
+ * Cleans the html of any none-html information.
350
+ *
351
+ * @param string $str
352
+ * @return string
353
+ */
354
+ protected function clean($str)
355
+ {
356
+ if ($this->options->get('cleanupInput') != true) {
357
+ // skip entire cleanup step
358
+ return $str;
359
+ }
360
+
361
+ // remove white space before closing tags
362
+ $str = mb_eregi_replace("'\s+>", "'>", $str);
363
+ $str = mb_eregi_replace('"\s+>', '">', $str);
364
+
365
+ // clean out the \n\r
366
+ $replace = ' ';
367
+ if ($this->options->get('preserveLineBreaks')) {
368
+ $replace = '&#10;';
369
+ }
370
+ $str = str_replace(["\r\n", "\r", "\n"], $replace, $str);
371
+
372
+ // strip the doctype
373
+ $str = mb_eregi_replace("<!doctype(.*?)>", '', $str);
374
+
375
+ // strip out comments
376
+ $str = mb_eregi_replace("<!--(.*?)-->", '', $str);
377
+
378
+ // strip out cdata
379
+ $str = mb_eregi_replace("<!\[CDATA\[(.*?)\]\]>", '', $str);
380
+
381
+ // strip out <script> tags
382
+ if ($this->options->get('removeScripts') == true) {
383
+ $str = mb_eregi_replace("<\s*script[^>]*[^/]>(.*?)<\s*/\s*script\s*>", '', $str);
384
+ $str = mb_eregi_replace("<\s*script\s*>(.*?)<\s*/\s*script\s*>", '', $str);
385
+ }
386
+
387
+ // strip out <style> tags
388
+ if ($this->options->get('removeStyles') == true) {
389
+ $str = mb_eregi_replace("<\s*style[^>]*[^/]>(.*?)<\s*/\s*style\s*>", '', $str);
390
+ $str = mb_eregi_replace("<\s*style\s*>(.*?)<\s*/\s*style\s*>", '', $str);
391
+ }
392
+
393
+ // strip out server side scripts
394
+ $str = mb_eregi_replace("(<\?)(.*?)(\?>)", '', $str);
395
+
396
+ // strip smarty scripts
397
+ $str = mb_eregi_replace("(\{\w)(.*?)(\})", '', $str);
398
+
399
+ return $str;
400
+ }
401
+
402
+ /**
403
+ * Attempts to parse the html in content.
404
+ */
405
+ protected function parse()
406
+ {
407
+ // add the root node
408
+ $this->root = new HtmlNode('root');
409
+ $activeNode = $this->root;
410
+ while ( ! is_null($activeNode)) {
411
+ $str = $this->content->copyUntil('<');
412
+ if ($str == '') {
413
+ $info = $this->parseTag();
414
+ if ( ! $info['status']) {
415
+ // we are done here
416
+ $activeNode = null;
417
+ continue;
418
+ }
419
+
420
+ // check if it was a closing tag
421
+ if ($info['closing']) {
422
+ $originalNode = $activeNode;
423
+ while ($activeNode->getTag()->name() != $info['tag']) {
424
+ $activeNode = $activeNode->getParent();
425
+ if (is_null($activeNode)) {
426
+ // we could not find opening tag
427
+ $activeNode = $originalNode;
428
+ break;
429
+ }
430
+ }
431
+ if ( ! is_null($activeNode)) {
432
+ $activeNode = $activeNode->getParent();
433
+ }
434
+ continue;
435
+ }
436
+
437
+ if ( ! isset($info['node'])) {
438
+ continue;
439
+ }
440
+
441
+ /** @var AbstractNode $node */
442
+ $node = $info['node'];
443
+ $activeNode->addChild($node);
444
+
445
+ // check if node is self closing
446
+ if ( ! $node->getTag()->isSelfClosing()) {
447
+ $activeNode = $node;
448
+ }
449
+ } else if ($this->options->whitespaceTextNode ||
450
+ trim($str) != ''
451
+ ) {
452
+ // we found text we care about
453
+ $textNode = new TextNode($str);
454
+ $activeNode->addChild($textNode);
455
+ }
456
+ }
457
+ }
458
+
459
+ /**
460
+ * Attempt to parse a tag out of the content.
461
+ *
462
+ * @return array
463
+ * @throws StrictException
464
+ */
465
+ protected function parseTag()
466
+ {
467
+ $return = [
468
+ 'status' => false,
469
+ 'closing' => false,
470
+ 'node' => null,
471
+ ];
472
+ if ($this->content->char() != '<') {
473
+ // we are not at the beginning of a tag
474
+ return $return;
475
+ }
476
+
477
+ // check if this is a closing tag
478
+ if ($this->content->fastForward(1)->char() == '/') {
479
+ // end tag
480
+ $tag = $this->content->fastForward(1)
481
+ ->copyByToken('slash', true);
482
+ // move to end of tag
483
+ $this->content->copyUntil('>');
484
+ $this->content->fastForward(1);
485
+
486
+ // check if this closing tag counts
487
+ $tag = strtolower($tag);
488
+ if (in_array($tag, $this->selfClosing)) {
489
+ $return['status'] = true;
490
+
491
+ return $return;
492
+ } else {
493
+ $return['status'] = true;
494
+ $return['closing'] = true;
495
+ $return['tag'] = strtolower($tag);
496
+ }
497
+
498
+ return $return;
499
+ }
500
+
501
+ $tag = strtolower($this->content->copyByToken('slash', true));
502
+ $node = new HtmlNode($tag);
503
+
504
+ // attributes
505
+ while ($this->content->char() != '>' &&
506
+ $this->content->char() != '/') {
507
+ $space = $this->content->skipByToken('blank', true);
508
+ if (empty($space)) {
509
+ $this->content->fastForward(1);
510
+ continue;
511
+ }
512
+
513
+ $name = $this->content->copyByToken('equal', true);
514
+ if ($name == '/') {
515
+ break;
516
+ }
517
+
518
+ if (empty($name)) {
519
+ $this->content->fastForward(1);
520
+ continue;
521
+ }
522
+
523
+ $this->content->skipByToken('blank');
524
+ if ($this->content->char() == '=') {
525
+ $attr = [];
526
+ $this->content->fastForward(1)
527
+ ->skipByToken('blank');
528
+ switch ($this->content->char()) {
529
+ case '"':
530
+ $attr['doubleQuote'] = true;
531
+ $this->content->fastForward(1);
532
+ $string = $this->content->copyUntil('"', true, true);
533
+ do {
534
+ $moreString = $this->content->copyUntilUnless('"', '=>');
535
+ $string .= $moreString;
536
+ } while ( ! empty($moreString));
537
+ $attr['value'] = $string;
538
+ $this->content->fastForward(1);
539
+ $node->getTag()->$name = $attr;
540
+ break;
541
+ case "'":
542
+ $attr['doubleQuote'] = false;
543
+ $this->content->fastForward(1);
544
+ $string = $this->content->copyUntil("'", true, true);
545
+ do {
546
+ $moreString = $this->content->copyUntilUnless("'", '=>');
547
+ $string .= $moreString;
548
+ } while ( ! empty($moreString));
549
+ $attr['value'] = $string;
550
+ $this->content->fastForward(1);
551
+ $node->getTag()->$name = $attr;
552
+ break;
553
+ default:
554
+ $attr['doubleQuote'] = true;
555
+ $attr['value'] = $this->content->copyByToken('attr', true);
556
+ $node->getTag()->$name = $attr;
557
+ break;
558
+ }
559
+ } else {
560
+ // no value attribute
561
+ if ($this->options->strict) {
562
+ // can't have this in strict html
563
+ $character = $this->content->getPosition();
564
+ throw new StrictException("Tag '$tag' has an attribute '$name' with out a value! (character #$character)");
565
+ }
566
+ $node->getTag()->$name = [
567
+ 'value' => null,
568
+ 'doubleQuote' => true,
569
+ ];
570
+ if ($this->content->char() != '>') {
571
+ $this->content->rewind(1);
572
+ }
573
+ }
574
+ }
575
+
576
+ $this->content->skipByToken('blank');
577
+ if ($this->content->char() == '/') {
578
+ // self closing tag
579
+ $node->getTag()->selfClosing();
580
+ $this->content->fastForward(1);
581
+ } elseif (in_array($tag, $this->selfClosing)) {
582
+
583
+ // Should be a self closing tag, check if we are strict
584
+ if ($this->options->strict) {
585
+ $character = $this->content->getPosition();
586
+ throw new StrictException("Tag '$tag' is not self closing! (character #$character)");
587
+ }
588
+
589
+ // We force self closing on this tag.
590
+ $node->getTag()->selfClosing();
591
+ }
592
+
593
+ $this->content->fastForward(1);
594
+
595
+ $return['status'] = true;
596
+ $return['node'] = $node;
597
+
598
+ return $return;
599
+ }
600
+
601
+ /**
602
+ * Attempts to detect the charset that the html was sent in.
603
+ *
604
+ * @return bool
605
+ */
606
+ protected function detectCharset()
607
+ {
608
+ // set the default
609
+ $encode = new Encode;
610
+ $encode->from($this->defaultCharset);
611
+ $encode->to($this->defaultCharset);
612
+
613
+ if ( ! is_null($this->options->enforceEncoding)) {
614
+ // they want to enforce the given encoding
615
+ $encode->from($this->options->enforceEncoding);
616
+ $encode->to($this->options->enforceEncoding);
617
+
618
+ return false;
619
+ }
620
+
621
+ $meta = $this->root->find('meta[http-equiv=Content-Type]', 0);
622
+ if (is_null($meta)) {
623
+ // could not find meta tag
624
+ $this->root->propagateEncoding($encode);
625
+
626
+ return false;
627
+ }
628
+ $content = $meta->content;
629
+ if (empty($content)) {
630
+ // could not find content
631
+ $this->root->propagateEncoding($encode);
632
+
633
+ return false;
634
+ }
635
+ $matches = [];
636
+ if (preg_match('/charset=(.+)/', $content, $matches)) {
637
+ $encode->from(trim($matches[1]));
638
+ $this->root->propagateEncoding($encode);
639
+
640
+ return true;
641
+ }
642
+
643
+ // no charset found
644
+ $this->root->propagateEncoding($encode);
645
+
646
+ return false;
647
+ }
648
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/AbstractNode.php ADDED
@@ -0,0 +1,410 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use PHPHtmlParser\Exceptions\CircularException;
5
+ use PHPHtmlParser\Exceptions\ParentNotFoundException;
6
+ use PHPHtmlParser\Selector;
7
+ use stringEncode\Encode;
8
+
9
+ /**
10
+ * Dom node object.
11
+ *
12
+ * @property string outerhtml
13
+ * @property string innerhtml
14
+ * @property string text
15
+ * @property \PHPHtmlParser\Dom\Tag tag
16
+ * @property InnerNode parent
17
+ */
18
+ abstract class AbstractNode
19
+ {
20
+
21
+ /**
22
+ * Contains the tag name/type
23
+ *
24
+ * @var \PHPHtmlParser\Dom\Tag
25
+ */
26
+ protected $tag;
27
+
28
+ /**
29
+ * Contains a list of attributes on this tag.
30
+ *
31
+ * @var array
32
+ */
33
+ protected $attr = [];
34
+
35
+ /**
36
+ * Contains the parent Node.
37
+ *
38
+ * @var InnerNode
39
+ */
40
+ protected $parent = null;
41
+
42
+ /**
43
+ * The unique id of the class. Given by PHP.
44
+ *
45
+ * @var string
46
+ */
47
+ protected $id;
48
+
49
+ /**
50
+ * The encoding class used to encode strings.
51
+ *
52
+ * @var mixed
53
+ */
54
+ protected $encode;
55
+
56
+ /**
57
+ * Creates a unique spl hash for this node.
58
+ */
59
+ public function __construct()
60
+ {
61
+ $this->id = spl_object_hash($this);
62
+ }
63
+
64
+ /**
65
+ * Magic get method for attributes and certain methods.
66
+ *
67
+ * @param string $key
68
+ * @return mixed
69
+ */
70
+ public function __get($key)
71
+ {
72
+ // check attribute first
73
+ if ( ! is_null($this->getAttribute($key))) {
74
+ return $this->getAttribute($key);
75
+ }
76
+ switch (strtolower($key)) {
77
+ case 'outerhtml':
78
+ return $this->outerHtml();
79
+ case 'innerhtml':
80
+ return $this->innerHtml();
81
+ case 'text':
82
+ return $this->text();
83
+ case 'tag':
84
+ return $this->getTag();
85
+ case 'parent':
86
+ $this->getParent();
87
+ }
88
+
89
+ return null;
90
+ }
91
+
92
+ /**
93
+ * Attempts to clear out any object references.
94
+ */
95
+ public function __destruct()
96
+ {
97
+ $this->tag = null;
98
+ $this->attr = [];
99
+ $this->parent = null;
100
+ $this->children = [];
101
+ }
102
+
103
+ /**
104
+ * Simply calls the outer text method.
105
+ *
106
+ * @return string
107
+ */
108
+ public function __toString()
109
+ {
110
+ return $this->outerHtml();
111
+ }
112
+
113
+ /**
114
+ * Returns the id of this object.
115
+ */
116
+ public function id()
117
+ {
118
+ return $this->id;
119
+ }
120
+
121
+ /**
122
+ * Returns the parent of node.
123
+ *
124
+ * @return AbstractNode
125
+ */
126
+ public function getParent()
127
+ {
128
+ return $this->parent;
129
+ }
130
+
131
+ /**
132
+ * Sets the parent node.
133
+ *
134
+ * @param InnerNode $parent
135
+ * @return $this
136
+ * @throws CircularException
137
+ */
138
+ public function setParent(InnerNode $parent)
139
+ {
140
+ // remove from old parent
141
+ if ( ! is_null($this->parent)) {
142
+ if ($this->parent->id() == $parent->id()) {
143
+ // already the parent
144
+ return $this;
145
+ }
146
+
147
+ $this->parent->removeChild($this->id);
148
+ }
149
+
150
+ $this->parent = $parent;
151
+
152
+ // assign child to parent
153
+ $this->parent->addChild($this);
154
+
155
+ //clear any cache
156
+ $this->clear();
157
+
158
+ return $this;
159
+ }
160
+
161
+ /**
162
+ * Removes this node and all its children from the
163
+ * DOM tree.
164
+ *
165
+ * @return void
166
+ */
167
+ public function delete()
168
+ {
169
+ if ( ! is_null($this->parent)) {
170
+ $this->parent->removeChild($this->id);
171
+ }
172
+
173
+ $this->parent = null;
174
+ }
175
+
176
+ /**
177
+ * Sets the encoding class to this node.
178
+ *
179
+ * @param Encode $encode
180
+ * @return void
181
+ */
182
+ public function propagateEncoding(Encode $encode)
183
+ {
184
+ $this->encode = $encode;
185
+ $this->tag->setEncoding($encode);
186
+ }
187
+
188
+ /**
189
+ * Checks if the given node id is an ancestor of
190
+ * the current node.
191
+ *
192
+ * @param int $id
193
+ * @return bool
194
+ */
195
+ public function isAncestor($id)
196
+ {
197
+ if ( ! is_null($this->getAncestor($id))) {
198
+ return true;
199
+ }
200
+
201
+ return false;
202
+ }
203
+
204
+ /**
205
+ * Attempts to get an ancestor node by the given id.
206
+ *
207
+ * @param int $id
208
+ * @return null|AbstractNode
209
+ */
210
+ public function getAncestor($id)
211
+ {
212
+ if ( ! is_null($this->parent)) {
213
+ if ($this->parent->id() == $id) {
214
+ return $this->parent;
215
+ }
216
+
217
+ return $this->parent->getAncestor($id);
218
+ }
219
+
220
+ return null;
221
+ }
222
+
223
+ /**
224
+ * Attempts to get the next sibling.
225
+ *
226
+ * @return AbstractNode
227
+ * @throws ParentNotFoundException
228
+ */
229
+ public function nextSibling()
230
+ {
231
+ if (is_null($this->parent)) {
232
+ throw new ParentNotFoundException('Parent is not set for this node.');
233
+ }
234
+
235
+ return $this->parent->nextChild($this->id);
236
+ }
237
+
238
+ /**
239
+ * Attempts to get the previous sibling
240
+ *
241
+ * @return AbstractNode
242
+ * @throws ParentNotFoundException
243
+ */
244
+ public function previousSibling()
245
+ {
246
+ if (is_null($this->parent)) {
247
+ throw new ParentNotFoundException('Parent is not set for this node.');
248
+ }
249
+
250
+ return $this->parent->previousChild($this->id);
251
+ }
252
+
253
+ /**
254
+ * Gets the tag object of this node.
255
+ *
256
+ * @return Tag
257
+ */
258
+ public function getTag()
259
+ {
260
+ return $this->tag;
261
+ }
262
+
263
+ /**
264
+ * A wrapper method that simply calls the getAttribute method
265
+ * on the tag of this node.
266
+ *
267
+ * @return array
268
+ */
269
+ public function getAttributes()
270
+ {
271
+ $attributes = $this->tag->getAttributes();
272
+ foreach ($attributes as $name => $info) {
273
+ $attributes[$name] = $info['value'];
274
+ }
275
+
276
+ return $attributes;
277
+ }
278
+
279
+ /**
280
+ * A wrapper method that simply calls the getAttribute method
281
+ * on the tag of this node.
282
+ *
283
+ * @param string $key
284
+ * @return mixed
285
+ */
286
+ public function getAttribute($key)
287
+ {
288
+ $attribute = $this->tag->getAttribute($key);
289
+ if ( ! is_null($attribute)) {
290
+ $attribute = $attribute['value'];
291
+ }
292
+
293
+ return $attribute;
294
+ }
295
+
296
+ /**
297
+ * A wrapper method that simply calls the setAttribute method
298
+ * on the tag of this node.
299
+ *
300
+ * @param string $key
301
+ * @param string $value
302
+ * @return $this
303
+ */
304
+ public function setAttribute($key, $value)
305
+ {
306
+ $this->tag->setAttribute($key, $value);
307
+
308
+ return $this;
309
+ }
310
+
311
+ /**
312
+ * A wrapper method that simply calls the removeAttribute method
313
+ * on the tag of this node.
314
+ *
315
+ * @param string $key
316
+ * @return void
317
+ */
318
+ public function removeAttribute($key)
319
+ {
320
+ $this->tag->removeAttribute($key);
321
+ }
322
+
323
+ /**
324
+ * A wrapper method that simply calls the removeAllAttributes
325
+ * method on the tag of this node.
326
+ *
327
+ * @return void
328
+ */
329
+ public function removeAllAttributes()
330
+ {
331
+ $this->tag->removeAllAttributes();
332
+ }
333
+
334
+ /**
335
+ * Function to locate a specific ancestor tag in the path to the root.
336
+ *
337
+ * @param string $tag
338
+ * @return AbstractNode
339
+ * @throws ParentNotFoundException
340
+ */
341
+ public function ancestorByTag($tag)
342
+ {
343
+ // Start by including ourselves in the comparison.
344
+ $node = $this;
345
+
346
+ while ( ! is_null($node)) {
347
+ if ($node->tag->name() == $tag) {
348
+ return $node;
349
+ }
350
+
351
+ $node = $node->getParent();
352
+ }
353
+
354
+ throw new ParentNotFoundException('Could not find an ancestor with "'.$tag.'" tag');
355
+ }
356
+
357
+ /**
358
+ * Find elements by css selector
359
+ *
360
+ * @param string $selector
361
+ * @param int $nth
362
+ * @return array|AbstractNode
363
+ */
364
+ public function find($selector, $nth = null)
365
+ {
366
+ $selector = new Selector($selector);
367
+ $nodes = $selector->find($this);
368
+
369
+ if ( ! is_null($nth)) {
370
+ // return nth-element or array
371
+ if (isset($nodes[$nth])) {
372
+ return $nodes[$nth];
373
+ }
374
+
375
+ return null;
376
+ }
377
+
378
+ return $nodes;
379
+ }
380
+
381
+ /**
382
+ * Gets the inner html of this node.
383
+ *
384
+ * @return string
385
+ */
386
+ abstract public function innerHtml();
387
+
388
+ /**
389
+ * Gets the html of this node, including it's own
390
+ * tag.
391
+ *
392
+ * @return string
393
+ */
394
+ abstract public function outerHtml();
395
+
396
+ /**
397
+ * Gets the text of this node (if there is any text).
398
+ *
399
+ * @return string
400
+ */
401
+ abstract public function text();
402
+
403
+ /**
404
+ * Call this when something in the node tree has changed. Like a child has been added
405
+ * or a parent has been changed.
406
+ *
407
+ * @return void
408
+ */
409
+ abstract protected function clear();
410
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/ArrayNode.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use Countable;
5
+ use ArrayIterator;
6
+ use IteratorAggregate;
7
+
8
+ /**
9
+ * Dom node object which will allow users to use it as
10
+ * an array.
11
+ */
12
+ abstract class ArrayNode extends AbstractNode implements IteratorAggregate, Countable
13
+ {
14
+
15
+ /**
16
+ * Gets the iterator
17
+ *
18
+ * @return ArrayIterator
19
+ */
20
+ public function getIterator()
21
+ {
22
+ return new ArrayIterator($this->getIteratorArray());
23
+ }
24
+
25
+ /**
26
+ * Returns the count of the iterator array.
27
+ *
28
+ * @return int
29
+ */
30
+ public function count()
31
+ {
32
+ return count($this->getIteratorArray());
33
+ }
34
+
35
+ /**
36
+ * Returns the array to be used the the iterator.
37
+ *
38
+ * @return array
39
+ */
40
+ abstract protected function getIteratorArray();
41
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/Collection.php ADDED
@@ -0,0 +1,168 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use ArrayAccess;
5
+ use ArrayIterator;
6
+ use Countable;
7
+ use IteratorAggregate;
8
+ use PHPHtmlParser\Exceptions\EmptyCollectionException;
9
+
10
+ /**
11
+ * Class Collection
12
+ *
13
+ * @package PHPHtmlParser\Dom
14
+ */
15
+ class Collection implements IteratorAggregate, ArrayAccess, Countable
16
+ {
17
+
18
+ /**
19
+ * The collection of Nodes.
20
+ *
21
+ * @param array
22
+ */
23
+ protected $collection = [];
24
+
25
+ /**
26
+ * Attempts to call the method on the first node in
27
+ * the collection.
28
+ *
29
+ * @param string $method
30
+ * @param array $arguments
31
+ * @return mixed;
32
+ * @throws EmptyCollectionException
33
+ */
34
+ public function __call($method, $arguments)
35
+ {
36
+ $node = reset($this->collection);
37
+ if ($node instanceof AbstractNode) {
38
+ return call_user_func_array([$node, $method], $arguments);
39
+ } else {
40
+ throw new EmptyCollectionException('The collection does not contain any Nodes.');
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Attempts to apply the magic get to the first node
46
+ * in the collection.
47
+ *
48
+ * @param mixed $key
49
+ * @return mixed
50
+ * @throws EmptyCollectionException
51
+ */
52
+ public function __get($key)
53
+ {
54
+ $node = reset($this->collection);
55
+ if ($node instanceof AbstractNode) {
56
+ return $node->$key;
57
+ } else {
58
+ throw new EmptyCollectionException('The collection does not contain any Nodes.');
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Applies the magic string method to the first node in
64
+ * the collection.
65
+ *
66
+ * @return string
67
+ * @throws EmptyCollectionException
68
+ */
69
+ public function __toString()
70
+ {
71
+ $node = reset($this->collection);
72
+ if ($node instanceof AbstractNode) {
73
+ return (string)$node;
74
+ } else {
75
+ throw new EmptyCollectionException('The collection does not contain any Nodes.');
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Returns the count of the collection.
81
+ *
82
+ * @return int
83
+ */
84
+ public function count()
85
+ {
86
+ return count($this->collection);
87
+ }
88
+
89
+ /**
90
+ * Returns an iterator for the collection.
91
+ *
92
+ * @return ArrayIterator
93
+ */
94
+ public function getIterator()
95
+ {
96
+ return new ArrayIterator($this->collection);
97
+ }
98
+
99
+ /**
100
+ * Set an attribute by the given offset
101
+ *
102
+ * @param mixed $offset
103
+ * @param mixed $value
104
+ */
105
+ public function offsetSet($offset, $value)
106
+ {
107
+ if (is_null($offset)) {
108
+ $this->collection[] = $value;
109
+ } else {
110
+ $this->collection[$offset] = $value;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Checks if an offset exists.
116
+ *
117
+ * @param mixed $offset
118
+ * @return bool
119
+ */
120
+ public function offsetExists($offset)
121
+ {
122
+ return isset($this->collection[$offset]);
123
+ }
124
+
125
+ /**
126
+ * Unset a collection Node.
127
+ *
128
+ * @param mixed $offset
129
+ */
130
+ public function offsetUnset($offset)
131
+ {
132
+ unset($this->collection[$offset]);
133
+ }
134
+
135
+ /**
136
+ * Gets a node at the given offset, or null
137
+ *
138
+ * @param mixed $offset
139
+ * @return mixed
140
+ */
141
+ public function offsetGet($offset)
142
+ {
143
+ return isset($this->collection[$offset]) ? $this->collection[$offset] : null;
144
+ }
145
+
146
+ /**
147
+ * Returns this collection as an array.
148
+ *
149
+ * @return array
150
+ */
151
+ public function toArray()
152
+ {
153
+ return $this->collection;
154
+ }
155
+
156
+ /**
157
+ * Similar to jQuery "each" method. Calls the callback with each
158
+ * Node in this collection.
159
+ *
160
+ * @param callback $callback
161
+ */
162
+ public function each($callback)
163
+ {
164
+ foreach ($this->collection as $key => $value) {
165
+ $callback($value, $key);
166
+ }
167
+ }
168
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/HtmlNode.php ADDED
@@ -0,0 +1,200 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use PHPHtmlParser\Exceptions\UnknownChildTypeException;
5
+ use PHPHtmlParser\Exceptions\ChildNotFoundException;
6
+
7
+ /**
8
+ * Class HtmlNode
9
+ *
10
+ * @package PHPHtmlParser\Dom
11
+ */
12
+ class HtmlNode extends InnerNode
13
+ {
14
+
15
+ /**
16
+ * Remembers what the innerHtml was if it was scanned previously.
17
+ */
18
+ protected $innerHtml = null;
19
+
20
+ /**
21
+ * Remembers what the outerHtml was if it was scanned previously.
22
+ *
23
+ * @var string
24
+ */
25
+ protected $outerHtml = null;
26
+
27
+ /**
28
+ * Remembers what the text was if it was scanned previously.
29
+ *
30
+ * @var string
31
+ */
32
+ protected $text = null;
33
+
34
+ /**
35
+ * Remembers what the text was when we looked into all our
36
+ * children nodes.
37
+ *
38
+ * @var string
39
+ */
40
+ protected $textWithChildren = null;
41
+
42
+ /**
43
+ * Sets up the tag of this node.
44
+ *
45
+ * @param $tag
46
+ */
47
+ public function __construct($tag)
48
+ {
49
+ if ( ! $tag instanceof Tag) {
50
+ $tag = new Tag($tag);
51
+ }
52
+ $this->tag = $tag;
53
+ parent::__construct();
54
+ }
55
+
56
+ /**
57
+ * Gets the inner html of this node.
58
+ *
59
+ * @return string
60
+ * @throws UnknownChildTypeException
61
+ */
62
+ public function innerHtml()
63
+ {
64
+ if ( ! $this->hasChildren()) {
65
+ // no children
66
+ return '';
67
+ }
68
+
69
+ if ( ! is_null($this->innerHtml)) {
70
+ // we already know the result.
71
+ return $this->innerHtml;
72
+ }
73
+
74
+ $child = $this->firstChild();
75
+ $string = '';
76
+
77
+ // continue to loop until we are out of children
78
+ while ( ! is_null($child)) {
79
+ if ($child instanceof TextNode) {
80
+ $string .= $child->text();
81
+ } elseif ($child instanceof HtmlNode) {
82
+ $string .= $child->outerHtml();
83
+ } else {
84
+ throw new UnknownChildTypeException('Unknown child type "'.get_class($child).'" found in node');
85
+ }
86
+
87
+ try {
88
+ $child = $this->nextChild($child->id());
89
+ } catch (ChildNotFoundException $e) {
90
+ // no more children
91
+ $child = null;
92
+ }
93
+ }
94
+
95
+ // remember the results
96
+ $this->innerHtml = $string;
97
+
98
+ return $string;
99
+ }
100
+
101
+ /**
102
+ * Gets the html of this node, including it's own
103
+ * tag.
104
+ *
105
+ * @return string
106
+ */
107
+ public function outerHtml()
108
+ {
109
+ // special handling for root
110
+ if ($this->tag->name() == 'root') {
111
+ return $this->innerHtml();
112
+ }
113
+
114
+ if ( ! is_null($this->outerHtml)) {
115
+ // we already know the results.
116
+ return $this->outerHtml;
117
+ }
118
+
119
+ $return = $this->tag->makeOpeningTag();
120
+ if ($this->tag->isSelfClosing()) {
121
+ // ignore any children... there should not be any though
122
+ return $return;
123
+ }
124
+
125
+ // get the inner html
126
+ $return .= $this->innerHtml();
127
+
128
+ // add closing tag
129
+ $return .= $this->tag->makeClosingTag();
130
+
131
+ // remember the results
132
+ $this->outerHtml = $return;
133
+
134
+ return $return;
135
+ }
136
+
137
+ /**
138
+ * Gets the text of this node (if there is any text). Or get all the text
139
+ * in this node, including children.
140
+ *
141
+ * @param bool $lookInChildren
142
+ * @return string
143
+ */
144
+ public function text($lookInChildren = false)
145
+ {
146
+ if ($lookInChildren) {
147
+ if ( ! is_null($this->textWithChildren)) {
148
+ // we already know the results.
149
+ return $this->textWithChildren;
150
+ }
151
+ } elseif ( ! is_null($this->text)) {
152
+ // we already know the results.
153
+ return $this->text;
154
+ }
155
+
156
+ // find out if this node has any text children
157
+ $text = '';
158
+ foreach ($this->children as $child) {
159
+ /** @var AbstractNode $node */
160
+ $node = $child['node'];
161
+ if ($node instanceof TextNode) {
162
+ $text .= $child['node']->text;
163
+ } elseif ($lookInChildren &&
164
+ $node instanceof HtmlNode
165
+ ) {
166
+ $text .= $node->text($lookInChildren);
167
+ }
168
+ }
169
+
170
+ // remember our result
171
+ if ($lookInChildren) {
172
+ $this->textWithChildren = $text;
173
+ } else {
174
+ $this->text = $text;
175
+ }
176
+
177
+ return $text;
178
+ }
179
+
180
+ /**
181
+ * Call this when something in the node tree has changed. Like a child has been added
182
+ * or a parent has been changed.
183
+ */
184
+ protected function clear()
185
+ {
186
+ $this->innerHtml = null;
187
+ $this->outerHtml = null;
188
+ $this->text = null;
189
+ }
190
+
191
+ /**
192
+ * Returns all children of this html node.
193
+ *
194
+ * @return array
195
+ */
196
+ protected function getIteratorArray()
197
+ {
198
+ return $this->getChildren();
199
+ }
200
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/InnerNode.php ADDED
@@ -0,0 +1,376 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use PHPHtmlParser\Exceptions\ChildNotFoundException;
5
+ use PHPHtmlParser\Exceptions\CircularException;
6
+ use stringEncode\Encode;
7
+
8
+ /**
9
+ * Inner node of the html tree, might have children.
10
+ *
11
+ * @package PHPHtmlParser\Dom
12
+ */
13
+ abstract class InnerNode extends ArrayNode
14
+ {
15
+
16
+ /**
17
+ * An array of all the children.
18
+ *
19
+ * @var array
20
+ */
21
+ protected $children = [];
22
+
23
+ /**
24
+ * Sets the encoding class to this node and propagates it
25
+ * to all its children.
26
+ *
27
+ * @param Encode $encode
28
+ * @return void
29
+ */
30
+ public function propagateEncoding(Encode $encode)
31
+ {
32
+ $this->encode = $encode;
33
+ $this->tag->setEncoding($encode);
34
+ // check children
35
+ foreach ($this->children as $id => $child) {
36
+ /** @var AbstractNode $node */
37
+ $node = $child['node'];
38
+ $node->propagateEncoding($encode);
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Checks if this node has children.
44
+ *
45
+ * @return bool
46
+ */
47
+ public function hasChildren()
48
+ {
49
+ return ! empty($this->children);
50
+ }
51
+
52
+ /**
53
+ * Returns the child by id.
54
+ *
55
+ * @param int $id
56
+ * @return AbstractNode
57
+ * @throws ChildNotFoundException
58
+ */
59
+ public function getChild($id)
60
+ {
61
+ if ( ! isset($this->children[$id])) {
62
+ throw new ChildNotFoundException("Child '$id' not found in this node.");
63
+ }
64
+
65
+ return $this->children[$id]['node'];
66
+ }
67
+
68
+ /**
69
+ * Returns a new array of child nodes
70
+ *
71
+ * @return array
72
+ */
73
+ public function getChildren()
74
+ {
75
+ $nodes = [];
76
+ try {
77
+ $child = $this->firstChild();
78
+ do {
79
+ $nodes[] = $child;
80
+ $child = $this->nextChild($child->id());
81
+ } while ( ! is_null($child));
82
+ } catch (ChildNotFoundException $e) {
83
+ // we are done looking for children
84
+ }
85
+
86
+ return $nodes;
87
+ }
88
+
89
+ /**
90
+ * Counts children
91
+ *
92
+ * @return int
93
+ */
94
+ public function countChildren()
95
+ {
96
+ return count($this->children);
97
+ }
98
+
99
+ /**
100
+ * Adds a child node to this node and returns the id of the child for this
101
+ * parent.
102
+ *
103
+ * @param AbstractNode $child
104
+ * @return bool
105
+ * @throws CircularException
106
+ */
107
+ public function addChild(AbstractNode $child, $before = null)
108
+ {
109
+ $key = null;
110
+
111
+ // check integrity
112
+ if ($this->isAncestor($child->id())) {
113
+ throw new CircularException('Can not add child. It is my ancestor.');
114
+ }
115
+
116
+ // check if child is itself
117
+ if ($child->id() == $this->id) {
118
+ throw new CircularException('Can not set itself as a child.');
119
+ }
120
+
121
+ $next = null;
122
+
123
+ if ($this->hasChildren()) {
124
+ if (isset($this->children[$child->id()])) {
125
+ // we already have this child
126
+ return false;
127
+ }
128
+
129
+ if ($before) {
130
+ if (!isset($this->children[$before])) {
131
+ return false;
132
+ }
133
+
134
+ $key = $this->children[$before]['prev'];
135
+
136
+ if($key){
137
+ $this->children[$key]['next'] = $child->id();
138
+ }
139
+
140
+ $this->children[$before]['prev'] = $child->id();
141
+ $next = $before;
142
+ } else {
143
+ $sibling = $this->lastChild();
144
+ $key = $sibling->id();
145
+
146
+ $this->children[$key]['next'] = $child->id();
147
+ }
148
+ }
149
+
150
+ $keys = array_keys($this->children);
151
+
152
+ $insert = [
153
+ 'node' => $child,
154
+ 'next' => $next,
155
+ 'prev' => $key,
156
+ ];
157
+
158
+ $index = $key ? (array_search($key, $keys, true) + 1) : 0;
159
+ array_splice($keys, $index, 0, $child->id());
160
+
161
+ $children = array_values($this->children);
162
+ array_splice($children, $index, 0, [$insert]);
163
+
164
+ // add the child
165
+ $this->children = array_combine($keys, $children);
166
+
167
+ // tell child I am the new parent
168
+ $child->setParent($this);
169
+
170
+ //clear any cache
171
+ $this->clear();
172
+
173
+ return true;
174
+ }
175
+
176
+ /**
177
+ * Insert element before child with provided id
178
+ *
179
+ * @param AbstractNode $child
180
+ * @return bool
181
+ * @param int $id
182
+ */
183
+ public function insertBefore(AbstractNode $child, $id){
184
+ $this->addChild($child, $id);
185
+ }
186
+
187
+ /**
188
+ * Insert element before after with provided id
189
+ *
190
+ * @param AbstractNode $child
191
+ * @return bool
192
+ * @param int $id
193
+ */
194
+ public function insertAfter(AbstractNode $child, $id){
195
+ if (!isset($this->children[$id])) {
196
+ return false;
197
+ }
198
+
199
+ if ($this->children[$id]['next']) {
200
+ return $this->addChild($child, $this->children[$id]['next']);
201
+ }
202
+
203
+ return $this->addChild($child);
204
+ }
205
+
206
+ /**
207
+ * Removes the child by id.
208
+ *
209
+ * @param int $id
210
+ * @return $this
211
+ */
212
+ public function removeChild($id)
213
+ {
214
+ if ( ! isset($this->children[$id])) {
215
+ return $this;
216
+ }
217
+
218
+ // handle moving next and previous assignments.
219
+ $next = $this->children[$id]['next'];
220
+ $prev = $this->children[$id]['prev'];
221
+ if ( ! is_null($next)) {
222
+ $this->children[$next]['prev'] = $prev;
223
+ }
224
+ if ( ! is_null($prev)) {
225
+ $this->children[$prev]['next'] = $next;
226
+ }
227
+
228
+ // remove the child
229
+ unset($this->children[$id]);
230
+
231
+ //clear any cache
232
+ $this->clear();
233
+
234
+ return $this;
235
+ }
236
+
237
+ /**
238
+ * Attempts to get the next child.
239
+ *
240
+ * @param int $id
241
+ * @return AbstractNode
242
+ * @uses $this->getChild()
243
+ * @throws ChildNotFoundException
244
+ */
245
+ public function nextChild($id)
246
+ {
247
+ $child = $this->getChild($id);
248
+ $next = $this->children[$child->id()]['next'];
249
+
250
+ return $this->getChild($next);
251
+ }
252
+
253
+ /**
254
+ * Attempts to get the previous child.
255
+ *
256
+ * @param int $id
257
+ * @return AbstractNode
258
+ * @uses $this->getChild()
259
+ * @throws ChildNotFoundException
260
+ */
261
+ public function previousChild($id)
262
+ {
263
+ $child = $this->getchild($id);
264
+ $next = $this->children[$child->id()]['prev'];
265
+
266
+ return $this->getChild($next);
267
+ }
268
+
269
+ /**
270
+ * Checks if the given node id is a child of the
271
+ * current node.
272
+ *
273
+ * @param int $id
274
+ * @return bool
275
+ */
276
+ public function isChild($id)
277
+ {
278
+ foreach ($this->children as $childId => $child) {
279
+ if ($id == $childId) {
280
+ return true;
281
+ }
282
+ }
283
+
284
+ return false;
285
+ }
286
+
287
+ /**
288
+ * Removes the child with id $childId and replace it with the new child
289
+ * $newChild.
290
+ *
291
+ * @param int $childId
292
+ * @param AbstractNode $newChild
293
+ * @throws ChildNotFoundException
294
+ */
295
+ public function replaceChild($childId, AbstractNode $newChild)
296
+ {
297
+ $oldChild = $this->getChild($childId);
298
+ $keys = array_keys($this->children);
299
+ $index = array_search($childId, $keys, true);
300
+ $keys[$index] = $newChild->id();
301
+ $this->children = array_combine($keys, $this->children);
302
+ $this->children[$newChild->id()] = $newChild;
303
+ unset($oldChild);
304
+ }
305
+
306
+ /**
307
+ * Shortcut to return the first child.
308
+ *
309
+ * @return AbstractNode
310
+ * @uses $this->getChild()
311
+ */
312
+ public function firstChild()
313
+ {
314
+ reset($this->children);
315
+ $key = key($this->children);
316
+
317
+ return $this->getChild($key);
318
+ }
319
+
320
+ /**
321
+ * Attempts to get the last child.
322
+ *
323
+ * @return AbstractNode
324
+ */
325
+ public function lastChild()
326
+ {
327
+ end($this->children);
328
+ $key = key($this->children);
329
+
330
+ return $this->getChild($key);
331
+ }
332
+
333
+ /**
334
+ * Checks if the given node id is a descendant of the
335
+ * current node.
336
+ *
337
+ * @param int $id
338
+ * @return bool
339
+ */
340
+ public function isDescendant($id)
341
+ {
342
+ if ($this->isChild($id)) {
343
+ return true;
344
+ }
345
+
346
+ foreach ($this->children as $childId => $child) {
347
+ /** @var InnerNode $node */
348
+ $node = $child['node'];
349
+ if ($node instanceof InnerNode &&
350
+ $node->hasChildren() &&
351
+ $node->isDescendant($id)
352
+ ) {
353
+ return true;
354
+ }
355
+ }
356
+
357
+ return false;
358
+ }
359
+
360
+ /**
361
+ * Sets the parent node.
362
+ *
363
+ * @param InnerNode $parent
364
+ * @return $this
365
+ * @throws CircularException
366
+ */
367
+ public function setParent(InnerNode $parent)
368
+ {
369
+ // check integrity
370
+ if ($this->isDescendant($parent->id())) {
371
+ throw new CircularException('Can not add descendant "'.$parent->id().'" as my parent.');
372
+ }
373
+
374
+ return parent::setParent($parent);
375
+ }
376
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/LeafNode.php ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+
5
+ /**
6
+ * Class LeafNode
7
+ *
8
+ * @package PHPHtmlParser
9
+ */
10
+ abstract class LeafNode extends AbstractNode
11
+ {
12
+
13
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/MockNode.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ /**
5
+ * This mock object is used solely for testing the abstract
6
+ * class Node with out any potential side effects caused
7
+ * by testing a supper class of Node.
8
+ *
9
+ * This object is not to be used for any other reason.
10
+ */
11
+ class MockNode extends InnerNode
12
+ {
13
+
14
+ /**
15
+ * Mock of innner html.
16
+ */
17
+ public function innerHtml()
18
+ {
19
+ }
20
+
21
+ /**
22
+ * Mock of outer html.
23
+ */
24
+ public function outerHtml()
25
+ {
26
+ }
27
+
28
+ /**
29
+ * Mock of text.
30
+ */
31
+ public function text()
32
+ {
33
+ }
34
+
35
+ /**
36
+ * Clear content of this node
37
+ */
38
+ protected function clear()
39
+ {
40
+ $this->innerHtml = null;
41
+ $this->outerHtml = null;
42
+ $this->text = null;
43
+ }
44
+
45
+ /**
46
+ * Returns all children of this html node.
47
+ *
48
+ * @return array
49
+ */
50
+ protected function getIteratorArray()
51
+ {
52
+ return $this->getChildren();
53
+ }
54
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/Tag.php ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ use PHPHtmlParser\Dom;
5
+ use stringEncode\Encode;
6
+
7
+ /**
8
+ * Class Tag
9
+ *
10
+ * @package PHPHtmlParser\Dom
11
+ */
12
+ class Tag
13
+ {
14
+
15
+ /**
16
+ * The name of the tag.
17
+ *
18
+ * @var string
19
+ */
20
+ protected $name;
21
+
22
+ /**
23
+ * The attributes of the tag.
24
+ *
25
+ * @var array
26
+ */
27
+ protected $attr = [];
28
+
29
+ /**
30
+ * Is this tag self closing.
31
+ *
32
+ * @var bool
33
+ */
34
+ protected $selfClosing = false;
35
+
36
+ /**
37
+ * Tag noise
38
+ */
39
+ protected $noise = '';
40
+
41
+ /**
42
+ * The encoding class to... encode the tags
43
+ *
44
+ * @var mixed
45
+ */
46
+ protected $encode = null;
47
+
48
+ /**
49
+ * Sets up the tag with a name.
50
+ *
51
+ * @param $name
52
+ */
53
+ public function __construct($name)
54
+ {
55
+ $this->name = $name;
56
+ }
57
+
58
+ /**
59
+ * Magic method to get any of the attributes.
60
+ *
61
+ * @param string $key
62
+ * @return mixed
63
+ */
64
+ public function __get($key)
65
+ {
66
+ return $this->getAttribute($key);
67
+ }
68
+
69
+ /**
70
+ * Magic method to set any attribute.
71
+ *
72
+ * @param string $key
73
+ * @param mixed $value
74
+ */
75
+ public function __set($key, $value)
76
+ {
77
+ $this->setAttribute($key, $value);
78
+ }
79
+
80
+ /**
81
+ * Returns the name of this tag.
82
+ *
83
+ * @return string
84
+ */
85
+ public function name()
86
+ {
87
+ return $this->name;
88
+ }
89
+
90
+ /**
91
+ * Sets the tag to be self closing.
92
+ *
93
+ * @return $this
94
+ */
95
+ public function selfClosing()
96
+ {
97
+ $this->selfClosing = true;
98
+
99
+ return $this;
100
+ }
101
+
102
+ /**
103
+ * Checks if the tag is self closing.
104
+ *
105
+ * @return bool
106
+ */
107
+ public function isSelfClosing()
108
+ {
109
+ return $this->selfClosing;
110
+ }
111
+
112
+ /**
113
+ * Sets the encoding type to be used.
114
+ *
115
+ * @param Encode $encode
116
+ */
117
+ public function setEncoding(Encode $encode)
118
+ {
119
+ $this->encode = $encode;
120
+ }
121
+
122
+ /**
123
+ * Sets the noise for this tag (if any)
124
+ *
125
+ * @param $noise
126
+ * @return $this
127
+ */
128
+ public function noise($noise)
129
+ {
130
+ $this->noise = $noise;
131
+
132
+ return $this;
133
+ }
134
+
135
+ /**
136
+ * Set an attribute for this tag.
137
+ *
138
+ * @param string $key
139
+ * @param string|array $value
140
+ * @return $this
141
+ */
142
+ public function setAttribute($key, $value)
143
+ {
144
+ $key = strtolower($key);
145
+ if ( ! is_array($value)) {
146
+ $value = [
147
+ 'value' => $value,
148
+ 'doubleQuote' => true,
149
+ ];
150
+ }
151
+ $this->attr[$key] = $value;
152
+
153
+ return $this;
154
+ }
155
+
156
+ /**
157
+ * Removes an attribute from this tag.
158
+ *
159
+ * @param $key
160
+ * @return void
161
+ */
162
+ public function removeAttribute($key)
163
+ {
164
+ $key = strtolower($key);
165
+ unset($this->attr[$key]);
166
+ }
167
+
168
+ /**
169
+ * Removes all attributes on this tag.
170
+ *
171
+ * @return void
172
+ */
173
+ public function removeAllAttributes()
174
+ {
175
+ $this->attr = [];
176
+ }
177
+
178
+ /**
179
+ * Sets the attributes for this tag
180
+ *
181
+ * @param array $attr
182
+ * @return $this
183
+ */
184
+ public function setAttributes(array $attr)
185
+ {
186
+ foreach ($attr as $key => $value) {
187
+ $this->setAttribute($key, $value);
188
+ }
189
+
190
+ return $this;
191
+ }
192
+
193
+ /**
194
+ * Returns all attributes of this tag.
195
+ *
196
+ * @return array
197
+ */
198
+ public function getAttributes()
199
+ {
200
+ $return = [];
201
+ foreach ($this->attr as $attr => $info) {
202
+ $return[$attr] = $this->getAttribute($attr);
203
+ }
204
+
205
+ return $return;
206
+ }
207
+
208
+ /**
209
+ * Returns an attribute by the key
210
+ *
211
+ * @param string $key
212
+ * @return mixed
213
+ */
214
+ public function getAttribute($key)
215
+ {
216
+ if ( ! isset($this->attr[$key])) {
217
+ return null;
218
+ }
219
+ $value = $this->attr[$key]['value'];
220
+ if (is_string($value) && ! is_null($this->encode)) {
221
+ // convert charset
222
+ $this->attr[$key]['value'] = $this->encode->convert($value);
223
+ }
224
+
225
+ return $this->attr[$key];
226
+ }
227
+
228
+ /**
229
+ * Generates the opening tag for this object.
230
+ *
231
+ * @return string
232
+ */
233
+ public function makeOpeningTag()
234
+ {
235
+ $return = '<'.$this->name;
236
+
237
+ // add the attributes
238
+ foreach ($this->attr as $key => $info) {
239
+ $info = $this->getAttribute($key);
240
+ $val = $info['value'];
241
+ if (is_null($val)) {
242
+ $return .= ' '.$key;
243
+ } elseif ($info['doubleQuote']) {
244
+ $return .= ' '.$key.'="'.$val.'"';
245
+ } else {
246
+ $return .= ' '.$key.'=\''.$val.'\'';
247
+ }
248
+ }
249
+
250
+ if ($this->selfClosing) {
251
+ return $return.' />';
252
+ } else {
253
+ return $return.'>';
254
+ }
255
+ }
256
+
257
+ /**
258
+ * Generates the closing tag for this object.
259
+ *
260
+ * @return string
261
+ */
262
+ public function makeClosingTag()
263
+ {
264
+ if ($this->selfClosing) {
265
+ return '';
266
+ }
267
+
268
+ return '</'.$this->name.'>';
269
+ }
270
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Dom/TextNode.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Dom;
3
+
4
+ /**
5
+ * Class TextNode
6
+ *
7
+ * @package PHPHtmlParser\Dom
8
+ */
9
+ class TextNode extends LeafNode
10
+ {
11
+
12
+ /**
13
+ * This is a text node.
14
+ *
15
+ * @var Tag
16
+ */
17
+ protected $tag;
18
+
19
+ /**
20
+ * This is the text in this node.
21
+ *
22
+ * @var string
23
+ */
24
+ protected $text;
25
+
26
+ /**
27
+ * This is the converted version of the text.
28
+ *
29
+ * @var string
30
+ */
31
+ protected $convertedText = null;
32
+
33
+ /**
34
+ * Sets the text for this node.
35
+ *
36
+ * @param string $text
37
+ */
38
+ public function __construct($text)
39
+ {
40
+ // remove double spaces
41
+ $text = mb_ereg_replace('\s+', ' ', $text);
42
+
43
+ // restore line breaks
44
+ $text = str_replace('&#10;', "\n", $text);
45
+
46
+ $this->text = $text;
47
+ $this->tag = new Tag('text');
48
+ parent::__construct();
49
+ }
50
+
51
+ /**
52
+ * Returns the text of this node.
53
+ *
54
+ * @return string
55
+ */
56
+ public function text()
57
+ {
58
+ // convert charset
59
+ if ( ! is_null($this->encode)) {
60
+ if ( ! is_null($this->convertedText)) {
61
+ // we already know the converted value
62
+ return $this->convertedText;
63
+ }
64
+ $text = $this->encode->convert($this->text);
65
+
66
+ // remember the conversion
67
+ $this->convertedText = $text;
68
+
69
+ return $text;
70
+ } else {
71
+ return $this->text;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * This node has no html, just return the text.
77
+ *
78
+ * @return string
79
+ * @uses $this->text()
80
+ */
81
+ public function innerHtml()
82
+ {
83
+ return $this->text();
84
+ }
85
+
86
+ /**
87
+ * This node has no html, just return the text.
88
+ *
89
+ * @return string
90
+ * @uses $this->text()
91
+ */
92
+ public function outerHtml()
93
+ {
94
+ return $this->text();
95
+ }
96
+
97
+ /**
98
+ * Call this when something in the node tree has changed. Like a child has been added
99
+ * or a parent has been changed.
100
+ */
101
+ protected function clear()
102
+ {
103
+ $this->convertedText = null;
104
+ }
105
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/ChildNotFoundException.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class ChildNotFoundException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class ChildNotFoundException extends \Exception
10
+ {
11
+ }
12
+
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/CircularException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class CircularException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class CircularException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/CurlException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class CurlException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ class CurlException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/EmptyCollectionException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class EmptyCollectionException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class EmptyCollectionException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/NotLoadedException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class NotLoadedException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class NotLoadedException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/ParentNotFoundException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class ParentNotFoundException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class ParentNotFoundException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/StrictException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class StrictException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class StrictException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Exceptions/UnknownChildTypeException.php ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser\Exceptions;
3
+
4
+ /**
5
+ * Class UnknownChildTypeException
6
+ *
7
+ * @package PHPHtmlParser\Exceptions
8
+ */
9
+ final class UnknownChildTypeException extends \Exception
10
+ {
11
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Options.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ /**
5
+ * Class Options
6
+ *
7
+ * @package PHPHtmlParser
8
+ * @property bool whitespaceTextNode
9
+ * @property bool strict
10
+ * @property bool enforceEncoding
11
+ */
12
+ class Options
13
+ {
14
+
15
+ /**
16
+ * The default options array
17
+ *
18
+ * @param array
19
+ */
20
+ protected $defaults = [
21
+ 'whitespaceTextNode' => true,
22
+ 'strict' => false,
23
+ 'enforceEncoding' => null,
24
+ 'cleanupInput' => true,
25
+ 'removeScripts' => true,
26
+ 'removeStyles' => true,
27
+ 'preserveLineBreaks' => false,
28
+ ];
29
+
30
+ /**
31
+ * The list of all current options set.
32
+ *
33
+ * @param array
34
+ */
35
+ protected $options = [];
36
+
37
+ /**
38
+ * Sets the default options in the options array
39
+ */
40
+ public function __construct()
41
+ {
42
+ $this->options = $this->defaults;
43
+ }
44
+
45
+ /**
46
+ * A magic get to call the get() method.
47
+ *
48
+ * @param string $key
49
+ * @return mixed
50
+ * @uses $this->get()
51
+ */
52
+ public function __get($key)
53
+ {
54
+ return $this->get($key);
55
+ }
56
+
57
+ /**
58
+ * Sets a new options param to override the current option array.
59
+ *
60
+ * @param array $options
61
+ * @return $this
62
+ */
63
+ public function setOptions(array $options)
64
+ {
65
+ foreach ($options as $key => $option) {
66
+ $this->options[$key] = $option;
67
+ }
68
+
69
+ return $this;
70
+ }
71
+
72
+ /**
73
+ * Gets the value associated to the key, or null if the key is not
74
+ * found.
75
+ *
76
+ * @param string
77
+ * @return mixed
78
+ */
79
+ public function get($key)
80
+ {
81
+ if (isset($this->options[$key])) {
82
+ return $this->options[$key];
83
+ }
84
+
85
+ return null;
86
+ }
87
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/Selector.php ADDED
@@ -0,0 +1,378 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ use PHPHtmlParser\Dom\AbstractNode;
5
+ use PHPHtmlParser\Dom\Collection;
6
+ use PHPHtmlParser\Dom\InnerNode;
7
+ use PHPHtmlParser\Dom\LeafNode;
8
+ use PHPHtmlParser\Exceptions\ChildNotFoundException;
9
+
10
+ /**
11
+ * Class Selector
12
+ *
13
+ * @package PHPHtmlParser
14
+ */
15
+ class Selector
16
+ {
17
+
18
+ /**
19
+ * Pattern of CSS selectors, modified from 'mootools'
20
+ *
21
+ * @var string
22
+ */
23
+ protected $pattern = "/([\w-:\*>]*)(?:\#([\w-]+)|\.([\w-]+))?(?:\[@?(!?[\w-:]+)(?:([!*^$]?=)[\"']?(.*?)[\"']?)?\])?([\/, ]+)/is";
24
+
25
+ protected $selectors = [];
26
+
27
+ /**
28
+ * Constructs with the selector string
29
+ *
30
+ * @param string $selector
31
+ */
32
+ public function __construct($selector)
33
+ {
34
+ $this->parseSelectorString($selector);
35
+ }
36
+
37
+ /**
38
+ * Returns the selectors that where found in __construct
39
+ *
40
+ * @return array
41
+ */
42
+ public function getSelectors()
43
+ {
44
+ return $this->selectors;
45
+ }
46
+
47
+ /**
48
+ * Attempts to find the selectors starting from the given
49
+ * node object.
50
+ *
51
+ * @param AbstractNode $node
52
+ * @return Collection
53
+ */
54
+ public function find(AbstractNode $node)
55
+ {
56
+ $results = new Collection;
57
+ foreach ($this->selectors as $selector) {
58
+ $nodes = [$node];
59
+ if (count($selector) == 0) {
60
+ continue;
61
+ }
62
+
63
+ $options = [];
64
+ foreach ($selector as $rule) {
65
+ if ($rule['alterNext']) {
66
+ $options[] = $this->alterNext($rule);
67
+ continue;
68
+ }
69
+ $nodes = $this->seek($nodes, $rule, $options);
70
+ // clear the options
71
+ $options = [];
72
+ }
73
+
74
+ // this is the final set of nodes
75
+ foreach ($nodes as $result) {
76
+ $results[] = $result;
77
+ }
78
+ }
79
+
80
+ return $results;
81
+ }
82
+
83
+ /**
84
+ * Parses the selector string
85
+ *
86
+ * @param string $selector
87
+ */
88
+ protected function parseSelectorString($selector)
89
+ {
90
+ $matches = [];
91
+ preg_match_all($this->pattern, trim($selector).' ', $matches, PREG_SET_ORDER);
92
+
93
+ // skip tbody
94
+ $result = [];
95
+ foreach ($matches as $match) {
96
+ // default values
97
+ $tag = strtolower(trim($match[1]));
98
+ $operator = '=';
99
+ $key = null;
100
+ $value = null;
101
+ $noKey = false;
102
+ $alterNext = false;
103
+
104
+ // check for elements that alter the behavior of the next element
105
+ if ($tag == '>') {
106
+ $alterNext = true;
107
+ }
108
+
109
+ // check for id selector
110
+ if ( ! empty($match[2])) {
111
+ $key = 'id';
112
+ $value = $match[2];
113
+ }
114
+
115
+ // check for class selector
116
+ if ( ! empty($match[3])) {
117
+ $key = 'class';
118
+ $value = $match[3];
119
+ }
120
+
121
+ // and final attribute selector
122
+ if ( ! empty($match[4])) {
123
+ $key = strtolower($match[4]);
124
+ }
125
+ if ( ! empty($match[5])) {
126
+ $operator = $match[5];
127
+ }
128
+ if ( ! empty($match[6])) {
129
+ $value = $match[6];
130
+ }
131
+
132
+ // check for elements that do not have a specified attribute
133
+ if (isset($key[0]) && $key[0] == '!') {
134
+ $key = substr($key, 1);
135
+ $noKey = true;
136
+ }
137
+
138
+ $result[] = [
139
+ 'tag' => $tag,
140
+ 'key' => $key,
141
+ 'value' => $value,
142
+ 'operator' => $operator,
143
+ 'noKey' => $noKey,
144
+ 'alterNext' => $alterNext,
145
+ ];
146
+ if (trim($match[7]) == ',') {
147
+ $this->selectors[] = $result;
148
+ $result = [];
149
+ }
150
+ }
151
+
152
+ // save last results
153
+ if (count($result) > 0) {
154
+ $this->selectors[] = $result;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Attempts to find all children that match the rule
160
+ * given.
161
+ *
162
+ * @param array $nodes
163
+ * @param array $rule
164
+ * @param array $options
165
+ * @return array
166
+ * @recursive
167
+ */
168
+ protected function seek(array $nodes, array $rule, array $options)
169
+ {
170
+ // XPath index
171
+ if (count($rule['tag']) > 0 &&
172
+ count($rule['key']) > 0 &&
173
+ is_numeric($rule['key'])
174
+ ) {
175
+ $count = 0;
176
+ /** @var AbstractNode $node */
177
+ foreach ($nodes as $node) {
178
+ if ($rule['tag'] == '*' ||
179
+ $rule['tag'] == $node->getTag()->name()
180
+ ) {
181
+ ++$count;
182
+ if ($count == $rule['key']) {
183
+ // found the node we wanted
184
+ return [$node];
185
+ }
186
+ }
187
+ }
188
+
189
+ return [];
190
+ }
191
+
192
+ $options = $this->flattenOptions($options);
193
+
194
+ $return = [];
195
+ /** @var InnerNode $node */
196
+ foreach ($nodes as $node) {
197
+ // check if we are a leaf
198
+ if ($node instanceof LeafNode ||
199
+ ! $node->hasChildren()
200
+ ) {
201
+ continue;
202
+ }
203
+
204
+ $children = [];
205
+ $child = $node->firstChild();
206
+ while ( ! is_null($child)) {
207
+ // wild card, grab all
208
+ if ($rule['tag'] == '*' && is_null($rule['key'])) {
209
+ $return[] = $child;
210
+ try {
211
+ $child = $node->nextChild($child->id());
212
+ } catch (ChildNotFoundException $e) {
213
+ // no more children
214
+ $child = null;
215
+ }
216
+ continue;
217
+ }
218
+
219
+ $pass = true;
220
+ // check tag
221
+ if ( ! empty($rule['tag']) && $rule['tag'] != $child->getTag()->name() &&
222
+ $rule['tag'] != '*'
223
+ ) {
224
+ // child failed tag check
225
+ $pass = false;
226
+ }
227
+
228
+ // check key
229
+ if ($pass && ! is_null($rule['key'])) {
230
+ if ($rule['noKey']) {
231
+ if ( ! is_null($child->getAttribute($rule['key']))) {
232
+ $pass = false;
233
+ }
234
+ } else {
235
+ if ($rule['key'] != 'plaintext' &&
236
+ is_null($child->getAttribute($rule['key']))
237
+ ) {
238
+ $pass = false;
239
+ }
240
+ }
241
+ }
242
+
243
+ // compare values
244
+ if ($pass && ! is_null($rule['key']) &&
245
+ ! is_null($rule['value']) && $rule['value'] != '*'
246
+ ) {
247
+ if ($rule['key'] == 'plaintext') {
248
+ // plaintext search
249
+ $nodeValue = $child->text();
250
+ } else {
251
+ // normal search
252
+ $nodeValue = $child->getAttribute($rule['key']);
253
+ }
254
+
255
+ $check = $this->match($rule['operator'], $rule['value'], $nodeValue);
256
+
257
+ // handle multiple classes
258
+ if ( ! $check && $rule['key'] == 'class') {
259
+ $childClasses = explode(' ', $child->getAttribute('class'));
260
+ foreach ($childClasses as $class) {
261
+ if ( ! empty($class)) {
262
+ $check = $this->match($rule['operator'], $rule['value'], $class);
263
+ }
264
+ if ($check) {
265
+ break;
266
+ }
267
+ }
268
+ }
269
+
270
+ if ( ! $check) {
271
+ $pass = false;
272
+ }
273
+ }
274
+
275
+ if ($pass) {
276
+ // it passed all checks
277
+ $return[] = $child;
278
+ } else {
279
+ // this child failed to be matched
280
+ if ($child instanceof InnerNode &&
281
+ $child->hasChildren()
282
+ ) {
283
+ // we still want to check its children
284
+ $children[] = $child;
285
+ }
286
+ }
287
+
288
+ try {
289
+ // get next child
290
+ $child = $node->nextChild($child->id());
291
+ } catch (ChildNotFoundException $e) {
292
+ // no more children
293
+ $child = null;
294
+ }
295
+ }
296
+
297
+ if (( ! isset($options['checkGrandChildren']) ||
298
+ $options['checkGrandChildren'])
299
+ && count($children) > 0
300
+ ) {
301
+ // we have children that failed but are not leaves.
302
+ $matches = $this->seek($children, $rule, $options);
303
+ foreach ($matches as $match) {
304
+ $return[] = $match;
305
+ }
306
+ }
307
+ }
308
+
309
+ return $return;
310
+ }
311
+
312
+ /**
313
+ * Attempts to match the given arguments with the given operator.
314
+ *
315
+ * @param string $operator
316
+ * @param string $pattern
317
+ * @param string $value
318
+ * @return bool
319
+ */
320
+ protected function match($operator, $pattern, $value)
321
+ {
322
+ $value = strtolower($value);
323
+ $pattern = strtolower($pattern);
324
+ switch ($operator) {
325
+ case '=':
326
+ return $value === $pattern;
327
+ case '!=':
328
+ return $value !== $pattern;
329
+ case '^=':
330
+ return preg_match('/^'.preg_quote($pattern, '/').'/', $value);
331
+ case '$=':
332
+ return preg_match('/'.preg_quote($pattern, '/').'$/', $value);
333
+ case '*=':
334
+ if ($pattern[0] == '/') {
335
+ return preg_match($pattern, $value);
336
+ }
337
+
338
+ return preg_match("/".$pattern."/i", $value);
339
+ }
340
+
341
+ return false;
342
+ }
343
+
344
+ /**
345
+ * Attempts to figure out what the alteration will be for
346
+ * the next element.
347
+ *
348
+ * @param array $rule
349
+ * @return array
350
+ */
351
+ protected function alterNext($rule)
352
+ {
353
+ $options = [];
354
+ if ($rule['tag'] == '>') {
355
+ $options['checkGrandChildren'] = false;
356
+ }
357
+
358
+ return $options;
359
+ }
360
+
361
+ /**
362
+ * Flattens the option array.
363
+ *
364
+ * @param array $optionsArray
365
+ * @return array
366
+ */
367
+ protected function flattenOptions(array $optionsArray)
368
+ {
369
+ $options = [];
370
+ foreach ($optionsArray as $optionArray) {
371
+ foreach ($optionArray as $key => $option) {
372
+ $options[$key] = $option;
373
+ }
374
+ }
375
+
376
+ return $options;
377
+ }
378
+ }
vendor/paquettg/php-html-parser/src/PHPHtmlParser/StaticDom.php ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace PHPHtmlParser;
3
+
4
+ use PHPHtmlParser\Exceptions\NotLoadedException;
5
+
6
+ /**
7
+ * Class StaticDom
8
+ *
9
+ * @package PHPHtmlParser
10
+ */
11
+ final class StaticDom
12
+ {
13
+
14
+ private static $dom = null;
15
+
16
+ /**
17
+ * Attempts to call the given method on the most recent created dom
18
+ * from bellow.
19
+ *
20
+ * @param string $method
21
+ * @param array $arguments
22
+ * @throws NotLoadedException
23
+ * @return mixed
24
+ */
25
+ public static function __callStatic($method, $arguments)
26
+ {
27
+ if (self::$dom instanceof Dom) {
28
+ return call_user_func_array([self::$dom, $method], $arguments);
29
+ } else {
30
+ throw new NotLoadedException('The dom is not loaded. Can not call a dom method.');
31
+ }
32
+ }
33
+
34
+ /**
35
+ * Call this to mount the static facade. The facade allows you to use
36
+ * this object as a $className.
37
+ *
38
+ * @param string $className
39
+ * @param Dom $dom
40
+ * @return bool
41
+ */
42
+ public static function mount($className = 'Dom', Dom $dom = null)
43
+ {
44
+ if (class_exists($className)) {
45
+ return false;
46
+ }
47
+ class_alias(__CLASS__, $className);
48
+ if ($dom instanceof Dom) {
49
+ self::$dom = $dom;
50
+ }
51
+
52
+ return true;
53
+ }
54
+
55
+ /**
56
+ * Creates a new dom object and calls load() on the
57
+ * new object.
58
+ *
59
+ * @param string $str
60
+ * @return $this
61
+ */
62
+ public static function load($str)
63
+ {
64
+ $dom = new Dom;
65
+ self::$dom = $dom;
66
+
67
+ return $dom->load($str);
68
+ }
69
+
70
+ /**
71
+ * Creates a new dom object and calls loadFromFile() on the
72
+ * new object.
73
+ *
74
+ * @param string $file
75
+ * @return $this
76
+ */
77
+ public static function loadFromFile($file)
78
+ {
79
+ $dom = new Dom;
80
+ self::$dom = $dom;
81
+
82
+ return $dom->loadFromFile($file);
83
+ }
84
+
85
+ /**
86
+ * Creates a new dom object and calls loadFromUrl() on the
87
+ * new object.
88
+ *
89
+ * @param string $url
90
+ * @param array $options
91
+ * @param CurlInterface $curl
92
+ * @return $this
93
+ */
94
+ public static function loadFromUrl($url, $options = [], CurlInterface $curl = null)
95
+ {
96
+ $dom = new Dom;
97
+ self::$dom = $dom;
98
+ if (is_null($curl)) {
99
+ // use the default curl interface
100
+ $curl = new Curl;
101
+ }
102
+
103
+ return $dom->loadFromUrl($url, $options, $curl);
104
+ }
105
+
106
+ /**
107
+ * Sets the $dom variable to null.
108
+ */
109
+ public static function unload()
110
+ {
111
+ self::$dom = null;
112
+ }
113
+ }
vendor/paquettg/php-html-parser/tests/CollectionTest.php ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Selector;
4
+ use PHPHtmlParser\Dom\HtmlNode;
5
+ use PHPHtmlParser\Dom\Tag;
6
+ use PHPHtmlParser\Dom\Collection;
7
+
8
+ class CollectionTest extends PHPUnit_Framework_TestCase {
9
+
10
+ public function testEach()
11
+ {
12
+ $root = new HtmlNode(new Tag('root'));
13
+ $parent = new HtmlNode(new Tag('div'));
14
+ $child1 = new HtmlNode(new Tag('a'));
15
+ $child2 = new HtmlNode(new Tag('p'));
16
+ $child3 = new HtmlNode(new Tag('a'));
17
+ $root->addChild($parent);
18
+ $parent->addChild($child1);
19
+ $parent->addChild($child2);
20
+ $child2->addChild($child3);
21
+
22
+ $selector = new Selector('a');
23
+ $collection = $selector->find($root);
24
+ $count = 0;
25
+ $collection->each(function ($node) use (&$count) {
26
+ ++$count;
27
+ });
28
+ $this->assertEquals(2, $count);
29
+ }
30
+
31
+ /**
32
+ * @expectedException PHPHtmlParser\Exceptions\EmptyCollectionException
33
+ */
34
+ public function testCallNoNodes()
35
+ {
36
+ $collection = new Collection();
37
+ $collection->innerHtml();
38
+ }
39
+
40
+ public function testCallMagic()
41
+ {
42
+ $root = new HtmlNode(new Tag('root'));
43
+ $parent = new HtmlNode(new Tag('div'));
44
+ $child1 = new HtmlNode(new Tag('a'));
45
+ $child2 = new HtmlNode(new Tag('p'));
46
+ $child3 = new HtmlNode(new Tag('a'));
47
+ $root->addChild($parent);
48
+ $parent->addChild($child1);
49
+ $parent->addChild($child2);
50
+ $child2->addChild($child3);
51
+
52
+ $selector = new Selector('div * a');
53
+ $this->assertEquals($child3->id(), $selector->find($root)->id());
54
+ }
55
+
56
+ public function testGetMagic()
57
+ {
58
+ $root = new HtmlNode(new Tag('root'));
59
+ $parent = new HtmlNode(new Tag('div'));
60
+ $child1 = new HtmlNode(new Tag('a'));
61
+ $child2 = new HtmlNode(new Tag('p'));
62
+ $child3 = new HtmlNode(new Tag('a'));
63
+ $root->addChild($parent);
64
+ $parent->addChild($child1);
65
+ $parent->addChild($child2);
66
+ $child2->addChild($child3);
67
+
68
+ $selector = new Selector('div * a');
69
+ $this->assertEquals($child3->innerHtml, $selector->find($root)->innerHtml);
70
+ }
71
+
72
+ /**
73
+ * @expectedException PHPHtmlParser\Exceptions\EmptyCollectionException
74
+ */
75
+ public function testGetNoNodes()
76
+ {
77
+ $collection = new Collection();
78
+ $collection->innerHtml;
79
+ }
80
+
81
+ public function testToStringMagic()
82
+ {
83
+ $root = new HtmlNode(new Tag('root'));
84
+ $parent = new HtmlNode(new Tag('div'));
85
+ $child1 = new HtmlNode(new Tag('a'));
86
+ $child2 = new HtmlNode(new Tag('p'));
87
+ $child3 = new HtmlNode(new Tag('a'));
88
+ $root->addChild($parent);
89
+ $parent->addChild($child1);
90
+ $parent->addChild($child2);
91
+ $child2->addChild($child3);
92
+
93
+ $selector = new Selector('div * a');
94
+ $this->assertEquals((string)$child3, (string)$selector->find($root));
95
+ }
96
+
97
+ public function testToArray()
98
+ {
99
+ $root = new HtmlNode(new Tag('root'));
100
+ $parent = new HtmlNode(new Tag('div'));
101
+ $child1 = new HtmlNode(new Tag('a'));
102
+ $child2 = new HtmlNode(new Tag('p'));
103
+ $child3 = new HtmlNode(new Tag('a'));
104
+ $root->addChild($parent);
105
+ $parent->addChild($child1);
106
+ $parent->addChild($child2);
107
+ $child2->addChild($child3);
108
+
109
+ $selector = new Selector('a');
110
+ $collection = $selector->find($root);
111
+ $array = $collection->toArray();
112
+ $lastA = end($array);
113
+ $this->assertEquals($child3->id(), $lastA->id());
114
+ }
115
+ }
vendor/paquettg/php-html-parser/tests/ContentTest.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Content;
4
+
5
+ class ContentTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testChar()
8
+ {
9
+ $content = new Content('abcde');
10
+ $this->assertEquals('a', $content->char());
11
+ }
12
+
13
+ public function testCharSelection()
14
+ {
15
+ $content = new Content('abcde');
16
+ $this->assertEquals('d', $content->char(3));
17
+ }
18
+
19
+ public function testFastForward()
20
+ {
21
+ $content = new Content('abcde');
22
+ $content->fastForward(2);
23
+ $this->assertEquals('c', $content->char());
24
+ }
25
+
26
+ public function testRewind()
27
+ {
28
+ $content = new Content('abcde');
29
+ $content->fastForward(2)
30
+ ->rewind(1);
31
+ $this->assertEquals('b', $content->char());
32
+ }
33
+
34
+ public function testRewindNegative()
35
+ {
36
+ $content = new Content('abcde');
37
+ $content->fastForward(2)
38
+ ->rewind(100);
39
+ $this->assertEquals('a', $content->char());
40
+ }
41
+
42
+ public function testCopyUntil()
43
+ {
44
+ $content = new Content('abcdeedcba');
45
+ $this->assertEquals('abcde', $content->copyUntil('ed'));
46
+ }
47
+
48
+ public function testCopyUntilChar()
49
+ {
50
+ $content = new Content('abcdeedcba');
51
+ $this->assertEquals('ab', $content->copyUntil('edc', true));
52
+ }
53
+
54
+ public function testCopyUntilEscape()
55
+ {
56
+ $content = new Content('foo\"bar"bax');
57
+ $this->assertEquals('foo\"bar', $content->copyUntil('"', false, true));
58
+ }
59
+
60
+ public function testCopyUntilNotFound()
61
+ {
62
+ $content = new Content('foo\"bar"bax');
63
+ $this->assertEquals('foo\"bar"bax', $content->copyUntil('baz'));
64
+ }
65
+
66
+ public function testCopyByToken()
67
+ {
68
+ $content = new Content('<a href="google.com">');
69
+ $content->fastForward(3);
70
+ $this->assertEquals('href="google.com"', $content->copyByToken('attr', true));
71
+ }
72
+
73
+ public function testSkip()
74
+ {
75
+ $content = new Content('abcdefghijkl');
76
+ $content->skip('abcd');
77
+ $this->assertEquals('e', $content->char());
78
+ }
79
+
80
+ public function testSkipCopy()
81
+ {
82
+ $content = new Content('abcdefghijkl');
83
+ $this->assertEquals('abcd', $content->skip('abcd', true));
84
+ }
85
+
86
+ public function testSkipByToken()
87
+ {
88
+ $content = new Content(' b c');
89
+ $content->fastForward(1);
90
+ $content->skipByToken('blank');
91
+ $this->assertEquals('b', $content->char());
92
+ }
93
+
94
+ }
vendor/paquettg/php-html-parser/tests/DomTest.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom;
4
+
5
+ class DomTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function tearDown()
8
+ {
9
+ Mockery::close();
10
+ }
11
+
12
+ public function testLoad()
13
+ {
14
+ $dom = new Dom;
15
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
16
+ $div = $dom->find('div', 0);
17
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>', $div->outerHtml);
18
+ }
19
+
20
+ /**
21
+ * @expectedException PHPHtmlParser\Exceptions\NotLoadedException
22
+ */
23
+ public function testNotLoaded()
24
+ {
25
+ $dom = new Dom;
26
+ $div = $dom->find('div', 0);
27
+ }
28
+
29
+ public function testIncorrectAccess()
30
+ {
31
+ $dom = new Dom;
32
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
33
+ $div = $dom->find('div', 0);
34
+ $this->assertEquals(null, $div->foo);
35
+ }
36
+
37
+ public function testLoadSelfclosingAttr()
38
+ {
39
+ $dom = new Dom;
40
+ $dom->load("<div class='all'><br foo bar />baz</div>");
41
+ $br = $dom->find('br', 0);
42
+ $this->assertEquals('<br foo bar />', $br->outerHtml);
43
+ }
44
+
45
+ public function testLoadSelfclosingAttrToString()
46
+ {
47
+ $dom = new Dom;
48
+ $dom->load("<div class='all'><br foo bar />baz</div>");
49
+ $br = $dom->find('br', 0);
50
+ $this->assertEquals('<br foo bar />', (string) $br);
51
+ }
52
+
53
+ public function testLoadEscapeQuotes()
54
+ {
55
+ $dom = new Dom;
56
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></div>');
57
+ $div = $dom->find('div', 0);
58
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></div>', $div->outerHtml);
59
+ }
60
+
61
+ public function testLoadNoOpeningTag()
62
+ {
63
+ $dom = new Dom;
64
+ $dom->load('<div class="all"><font color="red"><strong>PR Manager</strong></font></b><div class="content">content</div></div>');
65
+ $this->assertEquals('content', $dom->find('.content', 0)->text);
66
+ }
67
+
68
+ public function testLoadNoClosingTag()
69
+ {
70
+ $dom = new Dom;
71
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></div><br />');
72
+ $root = $dom->find('div', 0)->getParent();
73
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></div><br />', $root->outerHtml);
74
+ }
75
+
76
+ public function testLoadAttributeOnSelfClosing()
77
+ {
78
+ $dom = new Dom;
79
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></div><br class="both" />');
80
+ $br = $dom->find('br', 0);
81
+ $this->assertEquals('both', $br->getAttribute('class'));
82
+ }
83
+
84
+ public function testLoadClosingTagOnSelfClosing()
85
+ {
86
+ $dom = new Dom;
87
+ $dom->load('<div class="all"><br><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></br></div>');
88
+ $this->assertEquals('<br /><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p>', $dom->find('div', 0)->innerHtml);
89
+ }
90
+
91
+ public function testLoadClosingTagAddSelfClosingTag()
92
+ {
93
+ $dom = new Dom;
94
+ $dom->addSelfClosingTag('mytag');
95
+ $dom->load('<div class="all"><mytag><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></mytag></div>');
96
+ $this->assertEquals('<mytag /><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p>', $dom->find('div', 0)->innerHtml);
97
+ }
98
+
99
+ public function testLoadClosingTagAddSelfClosingTagArray()
100
+ {
101
+ $dom = new Dom;
102
+ $dom->addSelfClosingTag([
103
+ 'mytag',
104
+ 'othertag'
105
+ ]);
106
+ $dom->load('<div class="all"><mytag><p>Hey bro, <a href="google.com" data-quote="\"">click here</a><othertag></div>');
107
+ $this->assertEquals('<mytag /><p>Hey bro, <a href="google.com" data-quote="\"">click here</a><othertag /></p>', $dom->find('div', 0)->innerHtml);
108
+ }
109
+
110
+ public function testLoadClosingTagRemoveSelfClosingTag()
111
+ {
112
+ $dom = new Dom;
113
+ $dom->removeSelfClosingTag('br');
114
+ $dom->load('<div class="all"><br><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></br></div>');
115
+ $this->assertEquals('<br><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></br>', $dom->find('div', 0)->innerHtml);
116
+ }
117
+
118
+ public function testLoadClosingTagClearSelfClosingTag()
119
+ {
120
+ $dom = new Dom;
121
+ $dom->clearSelfClosingTags();
122
+ $dom->load('<div class="all"><br><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></br></div>');
123
+ $this->assertEquals('<br><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></br>', $dom->find('div', 0)->innerHtml);
124
+ }
125
+
126
+ public function testLoadNoValueAttribute()
127
+ {
128
+ $dom = new Dom;
129
+ $dom->load('<div class="content"><div class="grid-container" ui-view>Main content here</div></div>');
130
+ $this->assertEquals('<div class="content"><div class="grid-container" ui-view>Main content here</div></div>', $dom->innerHtml);
131
+ }
132
+
133
+ public function testLoadNoValueAttributeBefore()
134
+ {
135
+ $dom = new Dom;
136
+ $dom->load('<div class="content"><div ui-view class="grid-container">Main content here</div></div>');
137
+ $this->assertEquals('<div class="content"><div ui-view class="grid-container">Main content here</div></div>', $dom->innerHtml);
138
+ }
139
+
140
+ public function testLoadUpperCase()
141
+ {
142
+ $dom = new Dom;
143
+ $dom->load('<DIV CLASS="ALL"><BR><P>hEY BRO, <A HREF="GOOGLE.COM" DATA-QUOTE="\"">CLICK HERE</A></BR></DIV>');
144
+ $this->assertEquals('<br /><p>hEY BRO, <a href="GOOGLE.COM" data-quote="\"">CLICK HERE</a></p>', $dom->find('div', 0)->innerHtml);
145
+ }
146
+
147
+ public function testLoadWithFile()
148
+ {
149
+ $dom = new Dom;
150
+ $dom->loadFromFile('tests/files/small.html');
151
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-user font', 0)->text);
152
+ }
153
+
154
+ public function testLoadFromFile()
155
+ {
156
+ $dom = new Dom;
157
+ $dom->loadFromFile('tests/files/small.html');
158
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-user font', 0)->text);
159
+ }
160
+
161
+ public function testLoadFromFileFind()
162
+ {
163
+ $dom = new Dom;
164
+ $dom->loadFromFile('tests/files/small.html');
165
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-row div .post-user font', 0)->text);
166
+ }
167
+
168
+ public function testLoadUtf8()
169
+ {
170
+ $dom = new Dom;
171
+ $dom->load('<p>Dzień</p>');
172
+ $this->assertEquals('Dzień', $dom->find('p', 0)->text);
173
+ }
174
+
175
+ public function testLoadFileBig()
176
+ {
177
+ $dom = new Dom;
178
+ $dom->loadFromFile('tests/files/big.html');
179
+ $this->assertEquals(10, count($dom->find('.content-border')));
180
+ }
181
+
182
+ public function testLoadFileBigTwice()
183
+ {
184
+ $dom = new Dom;
185
+ $dom->loadFromFile('tests/files/big.html');
186
+ $post = $dom->find('.post-row', 0);
187
+ $this->assertEquals(' <p>Журчанье воды<br /> Черно-белые тени<br /> Вновь на фонтане</p> ', $post->find('.post-message', 0)->innerHtml);
188
+ }
189
+
190
+ public function testLoadFileBigTwicePreserveOption()
191
+ {
192
+ $dom = new Dom;
193
+ $dom->loadFromFile('tests/files/big.html', ['preserveLineBreaks' => true]);
194
+ $post = $dom->find('.post-row', 0);
195
+ $this->assertEquals('<p>Журчанье воды<br />
196
+ Черно-белые тени<br />
197
+ Вновь на фонтане</p>', trim($post->find('.post-message', 0)->innerHtml));
198
+ }
199
+
200
+ public function testLoadFromUrl()
201
+ {
202
+ $curl = Mockery::mock('PHPHtmlParser\CurlInterface');
203
+ $curl->shouldReceive('get')
204
+ ->once()
205
+ ->with('http://google.com')
206
+ ->andReturn(file_get_contents('tests/files/small.html'));
207
+
208
+ $dom = new Dom;
209
+ $dom->loadFromUrl('http://google.com', [], $curl);
210
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-row div .post-user font', 0)->text);
211
+ }
212
+
213
+ public function testToStringMagic()
214
+ {
215
+ $dom = new Dom;
216
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
217
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>', (string) $dom);
218
+ }
219
+
220
+ public function testGetMagic()
221
+ {
222
+ $dom = new Dom;
223
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
224
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>', $dom->innerHtml);
225
+ }
226
+
227
+ public function testFirstChild()
228
+ {
229
+ $dom = new Dom;
230
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></div><br />');
231
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></p></div>', $dom->firstChild()->outerHtml);
232
+ }
233
+
234
+ public function testLastChild()
235
+ {
236
+ $dom = new Dom;
237
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" data-quote="\"">click here</a></div><br />');
238
+ $this->assertEquals('<br />', $dom->lastChild()->outerHtml);
239
+ }
240
+
241
+ public function testGetElementById()
242
+ {
243
+ $dom = new Dom;
244
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" id="78">click here</a></div><br />');
245
+ $this->assertEquals('<a href="google.com" id="78">click here</a>', $dom->getElementById('78')->outerHtml);
246
+ }
247
+
248
+ public function testGetElementsByTag()
249
+ {
250
+ $dom = new Dom;
251
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" id="78">click here</a></div><br />');
252
+ $this->assertEquals('<p>Hey bro, <a href="google.com" id="78">click here</a></p>', $dom->getElementsByTag('p')[0]->outerHtml);
253
+ }
254
+
255
+ public function testGetElementsByClass()
256
+ {
257
+ $dom = new Dom;
258
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com" id="78">click here</a></div><br />');
259
+ $this->assertEquals('<p>Hey bro, <a href="google.com" id="78">click here</a></p>', $dom->getElementsByClass('all')[0]->innerHtml);
260
+ }
261
+
262
+ public function testEnforceEncoding()
263
+ {
264
+ $dom = new Dom;
265
+ $dom->load('tests/files/horrible.html', [
266
+ 'enforceEncoding' => 'UTF-8',
267
+ ]);
268
+ $this->assertNotEquals('<input type="submit" tabindex="0" name="submit" value="Информации" />', $dom->find('table input', 1)->outerHtml);
269
+ }
270
+
271
+ public function testScriptCleanerScriptTag()
272
+ {
273
+ $dom = new Dom;
274
+ $dom->load('
275
+ <p>.....</p>
276
+ <script>
277
+ Some code ...
278
+ document.write("<script src=\'some script\'><\/script>")
279
+ Some code ...
280
+ </script>
281
+ <p>....</p>');
282
+ $this->assertEquals('....', $dom->getElementsByTag('p')[1]->innerHtml);
283
+ }
284
+
285
+ public function testMultipleDoubleQuotes()
286
+ {
287
+ $dom = new Dom;
288
+ $dom->load('<a title="This is a "test" of double quotes" href="http://www.example.com">Hello</a>');
289
+ $this->assertEquals('This is a "test" of double quotes', $dom->getElementsByTag('a')[0]->title);
290
+ }
291
+
292
+ public function testMultipleSingleQuotes()
293
+ {
294
+ $dom = new Dom;
295
+ $dom->load("<a title='Ain't this the best' href=\"http://www.example.com\">Hello</a>");
296
+ $this->assertEquals("Ain't this the best", $dom->getElementsByTag('a')[0]->title);
297
+ }
298
+
299
+ public function testBeforeClosingTag()
300
+ {
301
+ $dom = new Dom;
302
+ $dom->load("<div class=\"stream-container \" > <div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\">");
303
+ $this->assertEquals("<div class=\"stream-container \"> <div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\"></div></div>", (string) $dom);
304
+ }
305
+
306
+ public function testCodeTag()
307
+ {
308
+ $dom = new Dom;
309
+ $dom->load('<strong>hello</strong><code class="language-php">$foo = "bar";</code>');
310
+ $this->assertEquals('<strong>hello</strong><code class="language-php">$foo = "bar";</code>', (string) $dom);
311
+ }
312
+
313
+ public function testDeleteNode()
314
+ {
315
+ $dom = new Dom;
316
+ $dom->load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
317
+ $a = $dom->find('a')[0];
318
+ $a->delete();
319
+ unset($a);
320
+ $this->assertEquals('<div class="all"><p>Hey bro, <br /> :)</p></div>', (string) $dom);
321
+ }
322
+ }
vendor/paquettg/php-html-parser/tests/Node/ChildrenTest.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom\MockNode as Node;
4
+
5
+ class NodeChildTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testGetParent()
8
+ {
9
+ $parent = new Node;
10
+ $child = new Node;
11
+ $child->setParent($parent);
12
+ $this->assertEquals($parent->id(), $child->getParent()->id());
13
+ }
14
+
15
+ public function testSetParentTwice()
16
+ {
17
+ $parent = new Node;
18
+ $parent2 = new Node;
19
+ $child = new Node;
20
+ $child->setParent($parent);
21
+ $child->setParent($parent2);
22
+ $this->assertEquals($parent2->id(), $child->getParent()->id());
23
+ }
24
+
25
+ public function testNextSibling()
26
+ {
27
+ $parent = new Node;
28
+ $child = new Node;
29
+ $child2 = new Node;
30
+ $child->setParent($parent);
31
+ $child2->setParent($parent);
32
+ $this->assertEquals($child2->id(), $child->nextSibling()->id());
33
+ }
34
+
35
+ /**
36
+ * @expectedException PHPHtmlParser\Exceptions\ChildNotFoundException
37
+ */
38
+ public function testNextSiblingNotFound()
39
+ {
40
+ $parent = new Node;
41
+ $child = new Node;
42
+ $child->setParent($parent);
43
+ $child->nextSibling();
44
+ }
45
+
46
+ /**
47
+ * @expectedException PHPHtmlParser\Exceptions\ParentNotFoundException
48
+ */
49
+ public function testNextSiblingNoParent()
50
+ {
51
+ $child = new Node;
52
+ $child->nextSibling();
53
+ }
54
+
55
+ public function testPreviousSibling()
56
+ {
57
+ $parent = new Node;
58
+ $child = new Node;
59
+ $child2 = new Node;
60
+ $child->setParent($parent);
61
+ $child2->setParent($parent);
62
+ $this->assertEquals($child->id(), $child2->previousSibling()->id());
63
+ }
64
+
65
+ /**
66
+ * @expectedException PHPHtmlParser\Exceptions\ChildNotFoundException
67
+ */
68
+ public function testPreviousSiblingNotFound()
69
+ {
70
+ $parent = new Node;
71
+ $node = new Node;
72
+ $node->setParent($parent);
73
+ $node->previousSibling();
74
+ }
75
+
76
+ /**
77
+ * @expectedException PHPHtmlParser\Exceptions\ParentNotFoundException
78
+ */
79
+ public function testPreviousSiblingNoParent()
80
+ {
81
+ $child = new Node;
82
+ $child->previousSibling();
83
+ }
84
+
85
+ public function testGetChildren()
86
+ {
87
+ $parent = new Node;
88
+ $child = new Node;
89
+ $child2 = new Node;
90
+ $child->setParent($parent);
91
+ $child2->setParent($parent);
92
+ $this->assertEquals($child->id(), $parent->getChildren()[0]->id());
93
+ }
94
+
95
+ public function testCountChildren()
96
+ {
97
+ $parent = new Node;
98
+ $child = new Node;
99
+ $child2 = new Node;
100
+ $child->setParent($parent);
101
+ $child2->setParent($parent);
102
+ $this->assertEquals(2, $parent->countChildren());
103
+ }
104
+
105
+ public function testIsChild ()
106
+ {
107
+ $parent = new Node;
108
+ $child1 = new Node;
109
+ $child2 = new Node;
110
+
111
+ $child1->setParent($parent);
112
+ $child2->setParent($child1);
113
+
114
+ $this->assertTrue ($parent->isChild ($child1->id ()));
115
+ $this->assertTrue ($parent->isDescendant ($child2->id ()));
116
+ $this->assertFalse ($parent->isChild ($child2->id ()));
117
+ }
118
+ }
vendor/paquettg/php-html-parser/tests/Node/HtmlTest.php ADDED
@@ -0,0 +1,459 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ use PHPHtmlParser\Dom\HtmlNode;
5
+ use PHPHtmlParser\Dom\TextNode;
6
+ use PHPHtmlParser\Dom\MockNode;
7
+ use PHPHtmlParser\Dom\Tag;
8
+
9
+ class NodeHtmlTest extends PHPUnit_Framework_TestCase {
10
+
11
+ public function testInnerHtml()
12
+ {
13
+ $div = new Tag('div');
14
+ $div->setAttributes([
15
+ 'class' => [
16
+ 'value' => 'all',
17
+ 'doubleQuote' => true,
18
+ ],
19
+ ]);
20
+ $a = new Tag('a');
21
+ $a->setAttributes([
22
+ 'href' => [
23
+ 'value' => 'http://google.com',
24
+ 'doubleQuote' => false,
25
+ ],
26
+ ]);
27
+ $br = new Tag('br');
28
+ $br->selfClosing();
29
+
30
+ $parent = new HtmlNode($div);
31
+ $childa = new HtmlNode($a);
32
+ $childbr = new HtmlNode($br);
33
+ $parent->addChild($childa);
34
+ $parent->addChild($childbr);
35
+ $childa->addChild(new TextNode('link'));
36
+
37
+ $this->assertEquals("<a href='http://google.com'>link</a><br />", $parent->innerHtml());
38
+ }
39
+
40
+ public function testInnerHtmlTwice()
41
+ {
42
+ $div = new Tag('div');
43
+ $div->setAttributes([
44
+ 'class' => [
45
+ 'value' => 'all',
46
+ 'doubleQuote' => true,
47
+ ],
48
+ ]);
49
+ $a = new Tag('a');
50
+ $br = new Tag('br');
51
+ $br->selfClosing();
52
+
53
+ $parent = new HtmlNode($div);
54
+ $childa = new HtmlNode($a);
55
+ $childa->setAttribute('href', [
56
+ 'value' => 'http://google.com',
57
+ 'doubleQuote' => false,
58
+ ]);
59
+ $childbr = new HtmlNode($br);
60
+ $parent->addChild($childa);
61
+ $parent->addChild($childbr);
62
+ $childa->addChild(new TextNode('link'));
63
+
64
+ $inner = $parent->innerHtml();
65
+ $this->assertEquals($inner, $parent->innerHtml());
66
+ }
67
+
68
+ /**
69
+ * @expectedException PHPHtmlParser\Exceptions\UnknownChildTypeException
70
+ */
71
+ public function testInnerHtmlUnkownChild()
72
+ {
73
+ $div = new Tag('div');
74
+ $div->setAttributes([
75
+ 'class' => [
76
+ 'value' => 'all',
77
+ 'doubleQuote' => true,
78
+ ],
79
+ ]);
80
+ $a = new Tag('a');
81
+ $a->setAttributes([
82
+ 'href' => [
83
+ 'value' => 'http://google.com',
84
+ 'doubleQuote' => false,
85
+ ],
86
+ ]);
87
+ $br = new Tag('br');
88
+ $br->selfClosing();
89
+
90
+ $parent = new HtmlNode($div);
91
+ $childa = new HtmlNode($a);
92
+ $childbr = new MockNode($br);
93
+ $parent->addChild($childa);
94
+ $parent->addChild($childbr);
95
+ $childa->addChild(new TextNode('link'));
96
+
97
+ $inner = $parent->innerHtml();
98
+ $this->assertEquals($inner, $parent->innerHtml());
99
+ }
100
+
101
+ public function testInnerHtmlMagic()
102
+ {
103
+ $parent = new HtmlNode('div');
104
+ $parent->tag->setAttributes([
105
+ 'class' => [
106
+ 'value' => 'all',
107
+ 'doubleQuote' => true,
108
+ ],
109
+ ]);
110
+ $childa = new HtmlNode('a');
111
+ $childa->getTag()->setAttributes([
112
+ 'href' => [
113
+ 'value' => 'http://google.com',
114
+ 'doubleQuote' => false,
115
+ ],
116
+ ]);
117
+ $childbr = new HtmlNode('br');
118
+ $childbr->getTag()->selfClosing();
119
+
120
+ $parent->addChild($childa);
121
+ $parent->addChild($childbr);
122
+ $childa->addChild(new TextNode('link'));
123
+
124
+ $this->assertEquals("<a href='http://google.com'>link</a><br />", $parent->innerHtml);
125
+ }
126
+
127
+ public function testOuterHtml()
128
+ {
129
+ $div = new Tag('div');
130
+ $div->setAttributes([
131
+ 'class' => [
132
+ 'value' => 'all',
133
+ 'doubleQuote' => true,
134
+ ],
135
+ ]);
136
+ $a = new Tag('a');
137
+ $a->setAttributes([
138
+ 'href' => [
139
+ 'value' => 'http://google.com',
140
+ 'doubleQuote' => false,
141
+ ],
142
+ ]);
143
+ $br = new Tag('br');
144
+ $br->selfClosing();
145
+
146
+ $parent = new HtmlNode($div);
147
+ $childa = new HtmlNode($a);
148
+ $childbr = new HtmlNode($br);
149
+ $parent->addChild($childa);
150
+ $parent->addChild($childbr);
151
+ $childa->addChild(new TextNode('link'));
152
+
153
+ $this->assertEquals('<div class="all"><a href=\'http://google.com\'>link</a><br /></div>', $parent->outerHtml());
154
+ }
155
+
156
+ public function testOuterHtmlTwice()
157
+ {
158
+ $div = new Tag('div');
159
+ $div->setAttributes([
160
+ 'class' => [
161
+ 'value' => 'all',
162
+ 'doubleQuote' => true,
163
+ ],
164
+ ]);
165
+ $a = new Tag('a');
166
+ $a->setAttributes([
167
+ 'href' => [
168
+ 'value' => 'http://google.com',
169
+ 'doubleQuote' => false,
170
+ ],
171
+ ]);
172
+ $br = new Tag('br');
173
+ $br->selfClosing();
174
+
175
+ $parent = new HtmlNode($div);
176
+ $childa = new HtmlNode($a);
177
+ $childbr = new HtmlNode($br);
178
+ $parent->addChild($childa);
179
+ $parent->addChild($childbr);
180
+ $childa->addChild(new TextNode('link'));
181
+
182
+ $outer = $parent->outerHtml();
183
+ $this->assertEquals($outer, $parent->outerHtml());
184
+ }
185
+
186
+ public function testOuterHtmlEmpty()
187
+ {
188
+ $a = new Tag('a');
189
+ $a->setAttributes([
190
+ 'href' => [
191
+ 'value' => 'http://google.com',
192
+ 'doubleQuote' => false,
193
+ ],
194
+ ]);
195
+ $node = new HtmlNode($a);
196
+
197
+ $this->assertEquals("<a href='http://google.com'></a>", $node->OuterHtml());
198
+ }
199
+
200
+ public function testOuterHtmlMagic()
201
+ {
202
+ $parent = new HtmlNode('div');
203
+ $parent->getTag()->setAttributes([
204
+ 'class' => [
205
+ 'value' => 'all',
206
+ 'doubleQuote' => true,
207
+ ],
208
+ ]);
209
+ $childa = new HtmlNode('a');
210
+ $childa->getTag()->setAttributes([
211
+ 'href' => [
212
+ 'value' => 'http://google.com',
213
+ 'doubleQuote' => false,
214
+ ],
215
+ ]);
216
+ $childbr = new HtmlNode('br');
217
+ $childbr->getTag()->selfClosing();
218
+
219
+ $parent->addChild($childa);
220
+ $parent->addChild($childbr);
221
+ $childa->addChild(new TextNode('link'));
222
+
223
+ $this->assertEquals('<div class="all"><a href=\'http://google.com\'>link</a><br /></div>', $parent->outerHtml);
224
+ }
225
+
226
+ public function testOuterHtmlNoValueAttribute()
227
+ {
228
+ $parent = new HtmlNode('div');
229
+ $parent->setAttribute('class', [
230
+ 'value' => 'all',
231
+ 'doubleQuote' => true,
232
+ ]);
233
+ $childa = new HtmlNode('a');
234
+ $childa->setAttribute('href', [
235
+ 'value' => 'http://google.com',
236
+ 'doubleQuote' => false,
237
+ ]);
238
+ $childa->setAttribute('ui-view', null);
239
+ $childbr = new HtmlNode('br');
240
+ $childbr->getTag()->selfClosing();
241
+
242
+ $parent->addChild($childa);
243
+ $parent->addChild($childbr);
244
+ $childa->addChild(new TextNode('link'));
245
+
246
+ $this->assertEquals('<div class="all"><a href=\'http://google.com\' ui-view>link</a><br /></div>', $parent->outerHtml);
247
+ }
248
+
249
+ public function testText()
250
+ {
251
+ $a = new Tag('a');
252
+ $node = new HtmlNode($a);
253
+ $node->addChild(new TextNode('link'));
254
+
255
+ $this->assertEquals('link', $node->text());
256
+ }
257
+
258
+ public function testTextTwice()
259
+ {
260
+ $a = new Tag('a');
261
+ $node = new HtmlNode($a);
262
+ $node->addChild(new TextNode('link'));
263
+
264
+ $text = $node->text();
265
+ $this->assertEquals($text, $node->text());
266
+ }
267
+
268
+ public function testTextNone()
269
+ {
270
+ $a = new Tag('a');
271
+ $node = new HtmlNode($a);
272
+
273
+ $this->assertEmpty($node->text());
274
+ }
275
+
276
+ public function testTextMagic()
277
+ {
278
+ $node = new HtmlNode('a');
279
+ $node->addChild(new TextNode('link'));
280
+
281
+ $this->assertEquals('link', $node->text);
282
+ }
283
+
284
+ public function testTextLookInChildren()
285
+ {
286
+ $p = new HtmlNode('p');
287
+ $a = new HtmlNode('a');
288
+ $a->addChild(new TextNode('click me'));
289
+ $p->addChild(new TextNode('Please '));
290
+ $p->addChild($a);
291
+ $p->addChild(new TextNode('!'));
292
+ $node = new HtmlNode('div');
293
+ $node->addChild($p);
294
+
295
+ $this->assertEquals('Please click me!', $node->text(true));
296
+ }
297
+
298
+ public function testTextLookInChildrenAndNoChildren()
299
+ {
300
+ $p = new HtmlNode('p');
301
+ $a = new HtmlNode('a');
302
+ $a->addChild(new TextNode('click me'));
303
+ $p->addChild(new TextNode('Please '));
304
+ $p->addChild($a);
305
+ $p->addChild(new TextNode('!'));
306
+
307
+ $p->text;
308
+ $p->text(true);
309
+
310
+ $this->assertEquals('Please click me!', $p->text(true));
311
+ }
312
+
313
+ public function testGetAttribute()
314
+ {
315
+ $node = new HtmlNode('a');
316
+ $node->getTag()->setAttributes([
317
+ 'href' => [
318
+ 'value' => 'http://google.com',
319
+ 'doubleQuote' => false,
320
+ ],
321
+ 'class' => [
322
+ 'value' => 'outerlink rounded',
323
+ 'doubleQuote' => true,
324
+ ],
325
+ ]);
326
+
327
+ $this->assertEquals('outerlink rounded', $node->getAttribute('class'));
328
+ }
329
+
330
+ public function testGetAttributeMagic()
331
+ {
332
+ $node = new HtmlNode('a');
333
+ $node->getTag()->setAttributes([
334
+ 'href' => [
335
+ 'value' => 'http://google.com',
336
+ 'doubleQuote' => false,
337
+ ],
338
+ 'class' => [
339
+ 'value' => 'outerlink rounded',
340
+ 'doubleQuote' => true,
341
+ ],
342
+ ]);
343
+
344
+ $this->assertEquals('http://google.com', $node->href);
345
+ }
346
+
347
+ public function testGetAttributes()
348
+ {
349
+ $node = new HtmlNode('a');
350
+ $node->getTag()->setAttributes([
351
+ 'href' => [
352
+ 'value' => 'http://google.com',
353
+ 'doubleQuote' => false,
354
+ ],
355
+ 'class' => [
356
+ 'value' => 'outerlink rounded',
357
+ 'doubleQuote' => true,
358
+ ],
359
+ ]);
360
+
361
+ $this->assertEquals('outerlink rounded', $node->getAttributes()['class']);
362
+ }
363
+
364
+ public function testSetAttribute()
365
+ {
366
+ $node = new HtmlNode('a');
367
+ $node->setAttribute('class', 'foo');
368
+ $this->assertEquals('foo', $node->getAttribute('class'));
369
+ }
370
+
371
+ public function testRemoveAttribute()
372
+ {
373
+ $node = new HtmlNode('a');
374
+ $node->setAttribute('class', 'foo');
375
+ $node->removeAttribute('class');
376
+ $this->assertnull($node->getAttribute('class'));
377
+ }
378
+
379
+ public function testRemoveAllAttributes()
380
+ {
381
+ $node = new HtmlNode('a');
382
+ $node->setAttribute('class', 'foo');
383
+ $node->setAttribute('href', 'http://google.com');
384
+ $node->removeAllAttributes();
385
+ $this->assertEquals(0, count($node->getAttributes()));
386
+ }
387
+
388
+ public function testCountable()
389
+ {
390
+ $div = new Tag('div');
391
+ $div->setAttributes([
392
+ 'class' => [
393
+ 'value' => 'all',
394
+ 'doubleQuote' => true,
395
+ ],
396
+ ]);
397
+ $a = new Tag('a');
398
+ $a->setAttributes([
399
+ 'href' => [
400
+ 'value' => 'http://google.com',
401
+ 'doubleQuote' => false,
402
+ ],
403
+ ]);
404
+ $br = new Tag('br');
405
+ $br->selfClosing();
406
+
407
+ $parent = new HtmlNode($div);
408
+ $childa = new HtmlNode($a);
409
+ $childbr = new HtmlNode($br);
410
+ $parent->addChild($childa);
411
+ $parent->addChild($childbr);
412
+ $childa->addChild(new TextNode('link'));
413
+
414
+ $this->assertEquals(count($parent->getChildren()), count($parent));
415
+ }
416
+
417
+ public function testIterator()
418
+ {
419
+ $div = new Tag('div');
420
+ $div->setAttributes([
421
+ 'class' => [
422
+ 'value' => 'all',
423
+ 'doubleQuote' => true,
424
+ ],
425
+ ]);
426
+ $a = new Tag('a');
427
+ $a->setAttributes([
428
+ 'href' => [
429
+ 'value' => 'http://google.com',
430
+ 'doubleQuote' => false,
431
+ ],
432
+ ]);
433
+ $br = new Tag('br');
434
+ $br->selfClosing();
435
+
436
+ $parent = new HtmlNode($div);
437
+ $childa = new HtmlNode($a);
438
+ $childbr = new HtmlNode($br);
439
+ $parent->addChild($childa);
440
+ $parent->addChild($childbr);
441
+ $childa->addChild(new TextNode('link'));
442
+
443
+ $children = 0;
444
+ foreach ($parent as $child) {
445
+ ++$children;
446
+ }
447
+ $this->assertEquals(2, $children);
448
+ }
449
+
450
+ /**
451
+ * @expectedException PHPHtmlParser\Exceptions\ParentNotFoundException
452
+ */
453
+ public function testAncestorByTagFailure()
454
+ {
455
+ $a = new Tag('a');
456
+ $node = new HtmlNode($a);
457
+ $node->ancestorByTag('div');
458
+ }
459
+ }
vendor/paquettg/php-html-parser/tests/Node/ParentTest.php ADDED
@@ -0,0 +1,219 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom\MockNode as Node;
4
+
5
+ class NodeParentTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testHasChild()
8
+ {
9
+ $parent = new Node;
10
+ $child = new Node;
11
+ $parent->addChild($child);
12
+ $this->assertTrue($parent->hasChildren());
13
+ }
14
+
15
+ public function testHasChildNoChildren()
16
+ {
17
+ $node = new Node;
18
+ $this->assertFalse($node->hasChildren());
19
+ }
20
+
21
+ public function testAddChild()
22
+ {
23
+ $parent = new Node;
24
+ $child = new Node;
25
+ $this->assertTrue($parent->addChild($child));
26
+ }
27
+
28
+ public function testAddChildTwoParent()
29
+ {
30
+ $parent = new Node;
31
+ $parent2 = new Node;
32
+ $child = new Node;
33
+ $parent->addChild($child);
34
+ $parent2->addChild($child);
35
+ $this->assertFalse($parent->hasChildren());
36
+ }
37
+
38
+ public function testGetChild()
39
+ {
40
+ $parent = new Node;
41
+ $child = new Node;
42
+ $child2 = new Node;
43
+ $parent->addChild($child);
44
+ $parent->addChild($child2);
45
+ $this->assertTrue($parent->getChild($child2->id()) instanceof Node);
46
+ }
47
+
48
+ public function testRemoveChild()
49
+ {
50
+ $parent = new Node;
51
+ $child = new Node;
52
+ $parent->addChild($child);
53
+ $parent->removeChild($child->id());
54
+ $this->assertFalse($parent->hasChildren());
55
+ }
56
+
57
+ public function testRemoveChildNotExists()
58
+ {
59
+ $parent = new Node;
60
+ $parent->removeChild(1);
61
+ $this->assertFalse($parent->hasChildren());
62
+ }
63
+
64
+ public function testNextChild()
65
+ {
66
+ $parent = new Node;
67
+ $child = new Node;
68
+ $child2 = new Node;
69
+ $parent->addChild($child);
70
+ $parent->addChild($child2);
71
+
72
+ $this->assertEquals($child2->id(), $parent->nextChild($child->id())->id());
73
+ }
74
+
75
+ public function testNextChildWithRemove()
76
+ {
77
+ $parent = new Node;
78
+ $child = new Node;
79
+ $child2 = new Node;
80
+ $child3 = new Node;
81
+ $parent->addChild($child);
82
+ $parent->addChild($child2);
83
+ $parent->addChild($child3);
84
+
85
+ $parent->removeChild($child2->id());
86
+ $this->assertEquals($child3->id(), $parent->nextChild($child->id())->id());
87
+ }
88
+
89
+ public function testPreviousChild()
90
+ {
91
+ $parent = new Node;
92
+ $child = new Node;
93
+ $child2 = new Node;
94
+ $parent->addChild($child);
95
+ $parent->addChild($child2);
96
+
97
+ $this->assertEquals($child->id(), $parent->previousChild($child2->id())->id());
98
+ }
99
+
100
+ public function testPreviousChildWithRemove()
101
+ {
102
+ $parent = new Node;
103
+ $child = new Node;
104
+ $child2 = new Node;
105
+ $child3 = new Node;
106
+ $parent->addChild($child);
107
+ $parent->addChild($child2);
108
+ $parent->addChild($child3);
109
+
110
+ $parent->removeChild($child2->id());
111
+ $this->assertEquals($child->id(), $parent->previousChild($child3->id())->id());
112
+ }
113
+
114
+ public function testFirstChild()
115
+ {
116
+ $parent = new Node;
117
+ $child = new Node;
118
+ $child2 = new Node;
119
+ $child3 = new Node;
120
+ $parent->addChild($child);
121
+ $parent->addChild($child2);
122
+ $parent->addChild($child3);
123
+
124
+ $this->assertEquals($child->id(), $parent->firstChild()->id());
125
+ }
126
+
127
+ public function testLastChild()
128
+ {
129
+ $parent = new Node;
130
+ $child = new Node;
131
+ $child2 = new Node;
132
+ $child3 = new Node;
133
+ $parent->addChild($child);
134
+ $parent->addChild($child2);
135
+ $parent->addChild($child3);
136
+
137
+ $this->assertEquals($child3->id(), $parent->lastChild()->id());
138
+ }
139
+
140
+ public function testReplaceChild()
141
+ {
142
+ $parent = new Node;
143
+ $child = new Node;
144
+ $child2 = new Node;
145
+ $child3 = new Node;
146
+ $parent->addChild($child);
147
+ $parent->addChild($child2);
148
+ $parent->replaceChild($child->id(), $child3);
149
+
150
+ $this->assertFalse($parent->isChild($child->id()));
151
+ }
152
+
153
+ /**
154
+ * @expectedException PHPHtmlParser\Exceptions\CircularException
155
+ */
156
+ public function testSetParentDescendantException()
157
+ {
158
+ $parent = new Node;
159
+ $child = new Node;
160
+ $parent->addChild($child);
161
+ $parent->setParent($child);
162
+ }
163
+
164
+ /**
165
+ * @expectedException PHPHtmlParser\Exceptions\CircularException
166
+ */
167
+ public function testAddChildAncestorException()
168
+ {
169
+ $parent = new Node;
170
+ $child = new Node;
171
+ $parent->addChild($child);
172
+ $child->addChild($parent);
173
+ }
174
+
175
+ /**
176
+ * @expectedException PHPHtmlParser\Exceptions\CircularException
177
+ */
178
+ public function testAddItselfAsChild()
179
+ {
180
+ $parent = new Node;
181
+ $parent->addChild($parent);
182
+ }
183
+
184
+
185
+ public function testIsAncestorParent()
186
+ {
187
+ $parent = new Node;
188
+ $child = new Node;
189
+ $parent->addChild($child);
190
+ $this->assertTrue($child->isAncestor($parent->id()));
191
+ }
192
+
193
+ public function testGetAncestor()
194
+ {
195
+ $parent = new Node;
196
+ $child = new Node;
197
+ $parent->addChild($child);
198
+ $ancestor = $child->getAncestor($parent->id());
199
+ $this->assertEquals($parent->id(), $ancestor->id());
200
+ }
201
+
202
+ public function testGetGreatAncestor()
203
+ {
204
+ $parent = new Node;
205
+ $child = new Node;
206
+ $child2 = new Node;
207
+ $parent->addChild($child);
208
+ $child->addChild($child2);
209
+ $ancestor = $child2->getAncestor($parent->id());
210
+ $this->assertEquals($parent->id(), $ancestor->id());
211
+ }
212
+
213
+ public function testGetAncestorNotFound()
214
+ {
215
+ $parent = new Node;
216
+ $ancestor = $parent->getAncestor(1);
217
+ $this->assertNull($ancestor);
218
+ }
219
+ }
vendor/paquettg/php-html-parser/tests/Node/TagTest.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom\Tag;
4
+
5
+ class NodeTagTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testSelfClosing()
8
+ {
9
+ $tag = new Tag('a');
10
+ $tag->selfClosing();
11
+ $this->assertTrue($tag->isSelfClosing());
12
+ }
13
+
14
+ public function testSetAttributes()
15
+ {
16
+ $attr = [
17
+ 'href' => [
18
+ 'value' => 'http://google.com',
19
+ 'doublequote' => false,
20
+ ],
21
+ ];
22
+
23
+ $tag = new Tag('a');
24
+ $tag->setAttributes($attr);
25
+ $this->assertEquals('http://google.com', $tag->getAttribute('href')['value']);
26
+ }
27
+
28
+ public function testRemoveAttribute()
29
+ {
30
+ $tag = new Tag('a');
31
+ $tag->setAttribute('href', 'http://google.com');
32
+ $tag->removeAttribute('href');
33
+ $this->assertNull($tag->getAttribute('href')['value']);
34
+ }
35
+
36
+ public function testRemoveAllAttributes()
37
+ {
38
+ $attr = [
39
+ 'class' => [
40
+ 'value' => 'clear-fix',
41
+ 'doubleQuote' => true,
42
+ ],
43
+ ];
44
+
45
+ $tag = new Tag('a');
46
+ $tag->setAttribute('href', 'http://google.com');
47
+ $tag->setAttribute('class', $attr);
48
+ $tag->removeAllAttributes();
49
+ $this->assertEquals(0, count($tag->getAttributes()));
50
+ }
51
+
52
+ public function testSetAttributeNoArray()
53
+ {
54
+ $tag = new Tag('a');
55
+ $tag->setAttribute('href', 'http://google.com');
56
+ $this->assertEquals('http://google.com', $tag->getAttribute('href')['value']);
57
+ }
58
+
59
+ public function testSetAttributesNoDoubleArray()
60
+ {
61
+ $attr = [
62
+ 'href' => 'http://google.com',
63
+ 'class' => 'funtimes',
64
+ ];
65
+
66
+ $tag = new Tag('a');
67
+ $tag->setAttributes($attr);
68
+ $this->assertEquals('funtimes', $tag->class['value']);
69
+ }
70
+
71
+ public function testNoise()
72
+ {
73
+ $tag = new Tag('a');
74
+ $this->assertTrue($tag->noise('noise') instanceof Tag);
75
+ }
76
+
77
+ public function testGetAttributeMagic()
78
+ {
79
+ $attr = [
80
+ 'href' => [
81
+ 'value' => 'http://google.com',
82
+ 'doublequote' => false,
83
+ ],
84
+ ];
85
+
86
+ $tag = new Tag('a');
87
+ $tag->setAttributes($attr);
88
+ $this->assertEquals('http://google.com', $tag->href['value']);
89
+ }
90
+
91
+ public function testSetAttributeMagic()
92
+ {
93
+ $tag = new Tag('a');
94
+ $tag->href = 'http://google.com';
95
+ $this->assertEquals('http://google.com', $tag->href['value']);
96
+ }
97
+
98
+ public function testMakeOpeningTag()
99
+ {
100
+ $attr = [
101
+ 'href' => [
102
+ 'value' => 'http://google.com',
103
+ 'doubleQuote' => true,
104
+ ],
105
+ ];
106
+
107
+ $tag = new Tag('a');
108
+ $tag->setAttributes($attr);
109
+ $this->assertEquals('<a href="http://google.com">', $tag->makeOpeningTag());
110
+ }
111
+
112
+ public function testMakeOpeningTagEmptyAttr()
113
+ {
114
+ $attr = [
115
+ 'href' => [
116
+ 'value' => 'http://google.com',
117
+ 'doubleQuote' => true,
118
+ ],
119
+ ];
120
+
121
+ $tag = new Tag('a');
122
+ $tag->setAttributes($attr);
123
+ $tag->selected = [
124
+ 'value' => null,
125
+ ];
126
+ $this->assertEquals('<a href="http://google.com" selected>', $tag->makeOpeningTag());
127
+ }
128
+
129
+ public function testMakeOpeningTagSelfClosing()
130
+ {
131
+ $attr = [
132
+ 'class' => [
133
+ 'value' => 'clear-fix',
134
+ 'doubleQuote' => true,
135
+ ],
136
+ ];
137
+
138
+ $tag = new Tag('div');
139
+ $tag->selfClosing()
140
+ ->setAttributes($attr);
141
+ $this->assertEquals('<div class="clear-fix" />', $tag->makeOpeningTag());
142
+ }
143
+
144
+ public function testMakeClosingTag()
145
+ {
146
+ $tag = new Tag('a');
147
+ $this->assertEquals('</a>', $tag->makeClosingTag());
148
+ }
149
+
150
+ public function testMakeClosingTagSelfClosing()
151
+ {
152
+ $tag = new Tag('div');
153
+ $tag->selfClosing();
154
+ $this->assertEmpty($tag->makeClosingTag());
155
+ }
156
+ }
vendor/paquettg/php-html-parser/tests/Node/TextTest.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom\TextNode;
4
+
5
+ class NodeTextTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testText()
8
+ {
9
+ $node = new TextNode('foo bar');
10
+ $this->assertEquals('foo bar', $node->text());
11
+ }
12
+
13
+ public function testGetTag()
14
+ {
15
+ $node = new TextNode('foo bar');
16
+ $this->assertEquals('text', $node->getTag()->name());
17
+ }
18
+
19
+ public function testAncestorByTag()
20
+ {
21
+ $node = new TextNode('foo bar');
22
+ $text = $node->ancestorByTag('text');
23
+ $this->assertEquals($node, $text);
24
+ }
25
+
26
+ public function testPreserveEntity()
27
+ {
28
+ $node = new TextNode('&#x69;');
29
+ $text = $node->innerhtml;
30
+ $this->assertEquals('&#x69;', $text);
31
+ }
32
+ }
vendor/paquettg/php-html-parser/tests/Options/CleanupTest.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom;
4
+
5
+ class CleanupTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testCleanupInputTrue()
8
+ {
9
+ $dom = new Dom;
10
+ $dom->setOptions([
11
+ 'cleanupInput' => true,
12
+ ]);
13
+ $dom->loadFromFile('tests/files/horrible.html');
14
+ $this->assertEquals(0, count($dom->find('style')));
15
+ $this->assertEquals(0, count($dom->find('script')));
16
+ }
17
+
18
+ public function testCleanupInputFalse()
19
+ {
20
+ $dom = new Dom;
21
+ $dom->setOptions([
22
+ 'cleanupInput' => false,
23
+ ]);
24
+ $dom->loadFromFile('tests/files/horrible.html');
25
+ $this->assertEquals(1, count($dom->find('style')));
26
+ $this->assertEquals(1, count($dom->find('script')));
27
+ }
28
+
29
+ public function testRemoveStylesTrue()
30
+ {
31
+ $dom = new Dom;
32
+ $dom->setOptions([
33
+ 'removeStyles' => true,
34
+ ]);
35
+ $dom->loadFromFile('tests/files/horrible.html');
36
+ $this->assertEquals(0, count($dom->find('style')));
37
+ }
38
+
39
+ public function testRemoveStylesFalse()
40
+ {
41
+ $dom = new Dom;
42
+ $dom->setOptions([
43
+ 'removeStyles' => false,
44
+ ]);
45
+ $dom->loadFromFile('tests/files/horrible.html');
46
+ $this->assertEquals(1, count($dom->find('style')));
47
+ $this->assertEquals('text/css',
48
+ $dom->find('style')->getAttribute('type'));
49
+ }
50
+
51
+ public function testRemoveScriptsTrue()
52
+ {
53
+ $dom = new Dom;
54
+ $dom->setOptions([
55
+ 'removeScripts' => true,
56
+ ]);
57
+ $dom->loadFromFile('tests/files/horrible.html');
58
+ $this->assertEquals(0, count($dom->find('script')));
59
+ }
60
+
61
+ public function testRemoveScriptsFalse()
62
+ {
63
+ $dom = new Dom;
64
+ $dom->setOptions([
65
+ 'removeScripts' => false,
66
+ ]);
67
+ $dom->loadFromFile('tests/files/horrible.html');
68
+ $this->assertEquals(1, count($dom->find('script')));
69
+ $this->assertEquals('text/JavaScript',
70
+ $dom->find('script')->getAttribute('type'));
71
+ }
72
+
73
+ }
vendor/paquettg/php-html-parser/tests/Options/PreserveLineBreaks.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom;
4
+
5
+ class PreserveLineBreaks extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testPreserveLineBreakTrue()
8
+ {
9
+ $dom = new Dom;
10
+ $dom->setOptions([
11
+ 'preserveLineBreaks' => true,
12
+ ]);
13
+ $dom->load("<div class=\"stream-container \">
14
+ <div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\">");
15
+
16
+ $this->assertEquals("<div class=\"stream-container \">\n<div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\"></div></div>", (string) $dom);
17
+ }
18
+
19
+ public function testPreserveLineBreakBeforeClosingTag()
20
+ {
21
+ $dom = new Dom;
22
+ $dom->setOptions([
23
+ 'preserveLineBreaks' => true,
24
+ ]);
25
+ $dom->load("<div class=\"stream-container \"
26
+ ><div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\">");
27
+
28
+ $this->assertEquals("<div class=\"stream-container \"><div class=\"stream-item js-new-items-bar-container\"> </div> <div class=\"stream\"></div></div>", (string) $dom);
29
+ }
30
+ }
vendor/paquettg/php-html-parser/tests/Options/StrictTest.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom;
4
+ use PHPHtmlParser\Exceptions\StrictException;
5
+
6
+ class StrictTest extends PHPUnit_Framework_TestCase {
7
+
8
+ public function testConfigStrict()
9
+ {
10
+ $dom = new Dom;
11
+ $dom->setOptions([
12
+ 'strict' => true,
13
+ ]);
14
+ $dom->load('<div><p id="hey">Hey you</p> <p id="ya">Ya you!</p></div>');
15
+ $this->assertEquals(' ', $dom->getElementById('hey')->nextSibling()->text);
16
+ }
17
+
18
+ public function testConfigStrictMissingSelfClosing()
19
+ {
20
+ $dom = new Dom;
21
+ $dom->setOptions([
22
+ 'strict' => true,
23
+ ]);
24
+ try
25
+ {
26
+ // should throw an exception
27
+ $dom->load('<div><p id="hey">Hey you</p><br><p id="ya">Ya you!</p></div>');
28
+ // we should not get here
29
+ $this->assertTrue(false);
30
+ }
31
+ catch (StrictException $e)
32
+ {
33
+ $this->assertEquals("Tag 'br' is not self closing! (character #31)", $e->getMessage());
34
+ }
35
+ }
36
+
37
+ public function testConfigStrictMissingAttribute()
38
+ {
39
+ $dom = new Dom;
40
+ $dom->setOptions([
41
+ 'strict' => true,
42
+ ]);
43
+ try
44
+ {
45
+ // should throw an exception
46
+ $dom->load('<div><p id="hey" block>Hey you</p> <p id="ya">Ya you!</p></div>');
47
+ // we should not get here
48
+ $this->assertTrue(false);
49
+ }
50
+ catch (StrictException $e)
51
+ {
52
+ $this->assertEquals("Tag 'p' has an attribute 'block' with out a value! (character #22)", $e->getMessage());
53
+ }
54
+ }
55
+ }
vendor/paquettg/php-html-parser/tests/Options/WhitespaceTextNodeTest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Dom;
4
+
5
+ class WhitespaceTextNodeTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testConfigGlobalNoWhitespaceTextNode()
8
+ {
9
+ $dom = new Dom;
10
+ $dom->setOptions([
11
+ 'whitespaceTextNode' => false,
12
+ ]);
13
+ $dom->load('<div><p id="hey">Hey you</p> <p id="ya">Ya you!</p></div>');
14
+ $this->assertEquals('Ya you!', $dom->getElementById('hey')->nextSibling()->text);
15
+ }
16
+
17
+ public function testConfigLocalOverride()
18
+ {
19
+ $dom = new Dom;
20
+ $dom->setOptions([
21
+ 'whitespaceTextNode' => false,
22
+ ]);
23
+ $dom->load('<div><p id="hey">Hey you</p> <p id="ya">Ya you!</p></div>', [
24
+ 'whitespaceTextNode' => true,
25
+ ]);
26
+ $this->assertEquals(' ', $dom->getElementById('hey')->nextSibling()->text);
27
+ }
28
+ }
vendor/paquettg/php-html-parser/tests/OptionsTest.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Options;
4
+
5
+ class OptionsTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testDefaultWhitespaceTextNode()
8
+ {
9
+ $options = new Options;
10
+
11
+ $this->assertTrue($options->whitespaceTextNode);
12
+ }
13
+
14
+ public function testAddingOption()
15
+ {
16
+ $options = new Options;
17
+ $options->setOptions([
18
+ 'test' => true,
19
+ ]);
20
+
21
+ $this->assertTrue($options->test);
22
+ }
23
+
24
+ public function testAddingOver()
25
+ {
26
+ $options = new Options;
27
+ $options->setOptions([
28
+ 'test' => false,
29
+ ])->setOptions([
30
+ 'test' => true,
31
+ 'whitespaceTextNode' => false,
32
+ ]);
33
+
34
+ $this->assertFalse($options->get('whitespaceTextNode'));
35
+ }
36
+
37
+ public function testGettingNoOption()
38
+ {
39
+ $options = new Options;
40
+ $this->assertEquals(null, $options->get('doesnotexist'));
41
+ }
42
+ }
43
+
vendor/paquettg/php-html-parser/tests/SelectorTest.php ADDED
@@ -0,0 +1,206 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\Selector;
4
+ use PHPHtmlParser\Dom\HtmlNode;
5
+ use PHPHtmlParser\Dom\Tag;
6
+
7
+ class SelectorTest extends PHPUnit_Framework_TestCase {
8
+
9
+ public function testParseSelectorStringId()
10
+ {
11
+ $selector = new Selector('#all');
12
+ $selectors = $selector->getSelectors();
13
+ $this->assertEquals('id', $selectors[0][0]['key']);
14
+ }
15
+
16
+ public function testParseSelectorStringClass()
17
+ {
18
+ $selector = new Selector('div.post');
19
+ $selectors = $selector->getSelectors();
20
+ $this->assertEquals('class', $selectors[0][0]['key']);
21
+ }
22
+
23
+ public function testParseSelectorStringAttribute()
24
+ {
25
+ $selector = new Selector('div[visible=yes]');
26
+ $selectors = $selector->getSelectors();
27
+ $this->assertEquals('yes', $selectors[0][0]['value']);
28
+ }
29
+
30
+ public function testParseSelectorStringNoKey()
31
+ {
32
+ $selector = new Selector('div[!visible]');
33
+ $selectors = $selector->getSelectors();
34
+ $this->assertTrue($selectors[0][0]['noKey']);
35
+ }
36
+
37
+ public function testFind()
38
+ {
39
+ $root = new HtmlNode('root');
40
+ $parent = new HtmlNode('div');
41
+ $child1 = new HtmlNode('a');
42
+ $child2 = new HtmlNode('p');
43
+ $parent->addChild($child1);
44
+ $parent->addChild($child2);
45
+ $root->addChild($parent);
46
+
47
+ $selector = new Selector('div a');
48
+ $this->assertEquals($child1->id(), $selector->find($root)[0]->id());
49
+ }
50
+
51
+ public function testFindId()
52
+ {
53
+ $parent = new HtmlNode(new Tag('div'));
54
+ $child1 = new HtmlNode(new Tag('a'));
55
+ $child2 = new HtmlNode(new Tag('p'));
56
+ $child2->getTag()->setAttributes([
57
+ 'id' => [
58
+ 'value' => 'content',
59
+ 'doubleQuote' => true,
60
+ ],
61
+ ]);
62
+ $parent->addChild($child1);
63
+ $parent->addChild($child2);
64
+
65
+ $selector = new Selector('#content');
66
+ $this->assertEquals($child2->id(), $selector->find($parent)[0]->id());
67
+ }
68
+
69
+ public function testFindClass()
70
+ {
71
+ $parent = new HtmlNode(new Tag('div'));
72
+ $child1 = new HtmlNode(new Tag('a'));
73
+ $child2 = new HtmlNode(new Tag('p'));
74
+ $child3 = new HtmlNode('a');
75
+ $child3->getTag()->setAttributes([
76
+ 'class' => [
77
+ 'value' => 'link',
78
+ 'doubleQuote' => true,
79
+ ],
80
+ ]);
81
+ $parent->addChild($child1);
82
+ $parent->addChild($child2);
83
+ $parent->addChild($child3);
84
+
85
+ $selector = new Selector('.link');
86
+ $this->assertEquals($child3->id(), $selector->find($parent)[0]->id());
87
+ }
88
+
89
+ public function testFindClassMultiple()
90
+ {
91
+ $parent = new HtmlNode(new Tag('div'));
92
+ $child1 = new HtmlNode(new Tag('a'));
93
+ $child2 = new HtmlNode(new Tag('p'));
94
+ $child3 = new HtmlNode(new Tag('a'));
95
+ $child3->getTag()->setAttributes([
96
+ 'class' => [
97
+ 'value' => 'link outer',
98
+ 'doubleQuote' => false,
99
+ ],
100
+ ]);
101
+ $parent->addChild($child1);
102
+ $parent->addChild($child2);
103
+ $parent->addChild($child3);
104
+
105
+ $selector = new Selector('.outer');
106
+ $this->assertEquals($child3->id(), $selector->find($parent)[0]->id());
107
+ }
108
+
109
+ public function testFindWild()
110
+ {
111
+ $root = new HtmlNode(new Tag('root'));
112
+ $parent = new HtmlNode(new Tag('div'));
113
+ $child1 = new HtmlNode(new Tag('a'));
114
+ $child2 = new HtmlNode(new Tag('p'));
115
+ $child3 = new HtmlNode(new Tag('a'));
116
+ $root->addChild($parent);
117
+ $parent->addChild($child1);
118
+ $parent->addChild($child2);
119
+ $child2->addChild($child3);
120
+
121
+ $selector = new Selector('div * a');
122
+ $this->assertEquals($child3->id(), $selector->find($root)[0]->id());
123
+ }
124
+
125
+ public function testFindMultipleSelectors()
126
+ {
127
+ $root = new HtmlNode(new Tag('root'));
128
+ $parent = new HtmlNode(new Tag('div'));
129
+ $child1 = new HtmlNode(new Tag('a'));
130
+ $child2 = new HtmlNode(new Tag('p'));
131
+ $child3 = new HtmlNode(new Tag('a'));
132
+ $root->addChild($parent);
133
+ $parent->addChild($child1);
134
+ $parent->addChild($child2);
135
+ $child2->addChild($child3);
136
+
137
+ $selector = new Selector('a, p');
138
+ $this->assertEquals(3, count($selector->find($root)));
139
+ }
140
+
141
+ public function testFindXpathKeySelector()
142
+ {
143
+ $parent = new HtmlNode(new Tag('div'));
144
+ $child1 = new HtmlNode(new Tag('a'));
145
+ $child2 = new HtmlNode(new Tag('p'));
146
+ $child3 = new HtmlNode(new Tag('a'));
147
+ $child3->getTag()->setAttributes([
148
+ 'class' => [
149
+ 'value' => 'link outer',
150
+ 'doubleQuote' => false,
151
+ ],
152
+ ]);
153
+ $parent->addChild($child1);
154
+ $parent->addChild($child2);
155
+ $parent->addChild($child3);
156
+
157
+ $selector = new Selector('div[1]');
158
+ $this->assertEquals($parent->id(), $selector->find($parent)[0]->id());
159
+ }
160
+
161
+ public function testFindChildMultipleLevelsDeep()
162
+ {
163
+ $root = new HtmlNode(new Tag('root'));
164
+ $parent = new HtmlNode(new Tag('div'));
165
+ $child1 = new HtmlNode(new Tag('ul'));
166
+ $child2 = new HtmlNode(new Tag('li'));
167
+ $root->addChild($parent);
168
+ $parent->addChild($child1);
169
+ $child1->addChild($child2);
170
+
171
+ $selector = new Selector('div li');
172
+ $this->assertEquals(1, count($selector->find($root)));
173
+ }
174
+
175
+ public function testFindAllChildren()
176
+ {
177
+ $root = new HtmlNode(new Tag('root'));
178
+ $parent = new HtmlNode(new Tag('div'));
179
+ $child1 = new HtmlNode(new Tag('ul'));
180
+ $child2 = new HtmlNode(new Tag('span'));
181
+ $child3 = new HtmlNode(new Tag('ul'));
182
+ $root->addChild($parent);
183
+ $parent->addChild($child1);
184
+ $child2->addChild($child3);
185
+ $parent->addChild($child2);
186
+
187
+ $selector = new Selector('div ul');
188
+ $this->assertEquals(2, count($selector->find($root)));
189
+ }
190
+
191
+ public function testFindChildUsingChildSelector()
192
+ {
193
+ $root = new HtmlNode(new Tag('root'));
194
+ $parent = new HtmlNode(new Tag('div'));
195
+ $child1 = new HtmlNode(new Tag('ul'));
196
+ $child2 = new HtmlNode(new Tag('span'));
197
+ $child3 = new HtmlNode(new Tag('ul'));
198
+ $root->addChild($parent);
199
+ $parent->addChild($child1);
200
+ $child2->addChild($child3);
201
+ $parent->addChild($child2);
202
+
203
+ $selector = new Selector('div > ul');
204
+ $this->assertEquals(1, count($selector->find($root)));
205
+ }
206
+ }
vendor/paquettg/php-html-parser/tests/StaticDomTest.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use PHPHtmlParser\StaticDom;
4
+
5
+ class StaticDomTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function setUp()
8
+ {
9
+ StaticDom::mount();
10
+ }
11
+
12
+ public function tearDown()
13
+ {
14
+ StaticDom::unload();
15
+ }
16
+
17
+ public function testMountWithDom()
18
+ {
19
+ $dom = new PHPHtmlParser\Dom;
20
+ StaticDom::unload();
21
+ $status = StaticDom::mount('newDom', $dom);
22
+ $this->assertTrue($status);
23
+ }
24
+
25
+ public function testLoad()
26
+ {
27
+ $dom = Dom::load('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>');
28
+ $div = $dom->find('div', 0);
29
+ $this->assertEquals('<div class="all"><p>Hey bro, <a href="google.com">click here</a><br /> :)</p></div>', $div->outerHtml);
30
+ }
31
+
32
+ public function testLoadWithFile()
33
+ {
34
+ $dom = Dom::load('tests/files/small.html');
35
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-user font', 0)->text);
36
+ }
37
+
38
+ public function testLoadFromFile()
39
+ {
40
+ $dom = Dom::loadFromFile('tests/files/small.html');
41
+ $this->assertEquals('VonBurgermeister', $dom->find('.post-user font', 0)->text);
42
+ }
43
+
44
+ public function testFind()
45
+ {
46
+ Dom::load('tests/files/horrible.html');
47
+ $this->assertEquals('<input type="submit" tabindex="0" name="submit" value="Информации" />', Dom::find('table input', 1)->outerHtml);
48
+ }
49
+
50
+ /**
51
+ * @expectedException PHPHtmlParser\Exceptions\NotLoadedException
52
+ */
53
+ public function testFindNoLoad()
54
+ {
55
+ Dom::find('.post-user font', 0);
56
+ }
57
+
58
+ public function testFindI()
59
+ {
60
+ Dom::load('tests/files/horrible.html');
61
+ $this->assertEquals('[ Досие бр:12928 ]', Dom::find('i')[0]->innerHtml);
62
+ }
63
+
64
+ public function testLoadFromUrl()
65
+ {
66
+ $curl = Mockery::mock('PHPHtmlParser\CurlInterface');
67
+ $curl->shouldReceive('get')
68
+ ->once()
69
+ ->with('http://google.com')
70
+ ->andReturn(file_get_contents('tests/files/small.html'));
71
+
72
+ Dom::loadFromUrl('http://google.com', [], $curl);
73
+ $this->assertEquals('VonBurgermeister', Dom::find('.post-row div .post-user font', 0)->text);
74
+ }
75
+
76
+ }
vendor/paquettg/php-html-parser/tests/files/big.html ADDED
@@ -0,0 +1,1464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+
3
+ <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="ru">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="generator" content="vBulletin 3.8.3" />
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
8
+
9
+ <meta name="keywords" content=" Поэтический конкурс хайку, " />
10
+ <meta name="description" content=" Поэтический конкурс хайку Литературное творчество" />
11
+
12
+
13
+
14
+ <!-- CSS Stylesheet -->
15
+
16
+ <link rel="stylesheet" type="text/css" media="all" href="http://cdn.leagueoflegends.com/lolkit/1.1.6/lol-kit.css" />
17
+ <link rel="stylesheet" type="text/css" media="all" href="/board/riot-assets/css/lol20/reskin.css" />
18
+ <link rel="SHORTCUT ICON" href="http://cdn.leagueoflegends.com/lolkit/1.1.6/resources/images/favicon.ico"/>
19
+
20
+
21
+
22
+ <!-- / CSS Stylesheet -->
23
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/yui/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js?v=387"></script>
24
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/yui/2.9.0/build/connection/connection-min.js?v=387"></script>
25
+ <script type="text/javascript">
26
+ <!--
27
+ var SESSIONURL = "";
28
+ var SECURITYTOKEN = "guest";
29
+ var IMGDIR_MISC = "images/misc";
30
+ var vb_disable_ajax = parseInt("0", 10);
31
+ // -->
32
+ </script>
33
+ <script type="text/javascript" src="clientscript/vbulletin_global.js?v=387"></script>
34
+
35
+ <script type="text/javascript" src="clientscript/vbulletin_menu.js?v=387"></script>
36
+
37
+
38
+
39
+ <link rel="alternate" type="application/rss+xml" title="Сообщество League of Legends RSS Feed" href="external.php?type=RSS2" />
40
+
41
+ <link rel="alternate" type="application/rss+xml" title="Сообщество League of Legends - Литературное творчество - RSS Feed" href="external.php?type=RSS2&amp;forumids=69" />
42
+
43
+
44
+
45
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
46
+ <script type="text/javascript" src="http://riot-web-static.s3.amazonaws.com/forum/community_v2/js/jquery.ddm.base.js"></script>
47
+ <script type="text/javascript" src="http://riot-web-static.s3.amazonaws.com/forum/community_v2/js/jquery.menus.js"></script>
48
+ <script type="text/javascript" src="http://riot-web-static.s3.amazonaws.com/forum/community_v2/js/jquery.cookie.js"></script>
49
+ <script type="text/javascript" src="http://riot-web-static.s3.amazonaws.com/forum/community_v2/js/jquery.stm.js"></script>
50
+
51
+
52
+
53
+ <script>
54
+ $(document).ready(function(){
55
+ $('#block-menu-primary-links ul.menu').dropDownMenu({timer: 250});
56
+ });
57
+ </script>
58
+
59
+ <script type="text/javascript">
60
+ function ChangeColor(tableRow, highLight) {
61
+ }
62
+
63
+ function DoNav(theUrl){
64
+ document.location.href = theUrl;
65
+ }
66
+ </script>
67
+ <script type="text/javascript" src="http://cdn.leagueoflegends.com/lolkit/1.1.6/modernizr.js"></script>
68
+ <title> Поэтический конкурс хайку - Страница 14 - Сообщество League of Legends</title>
69
+
70
+ </head>
71
+
72
+ <body class="internal pvpnetbar i18n-ru">
73
+ <!-- BACKGROUND -->
74
+ <div class="backdrop"></div>
75
+
76
+ <!-- HEADER -->
77
+
78
+
79
+ <script type="text/javascript" src="http://sandworm.cdn.leagueoflegends.com/loader.ru_RU.js"></script>
80
+ <script type="text/javascript">
81
+ <!--//--><![CDATA[//><!--
82
+ Riot.Sandworm.setLang("ru_RU");
83
+ Riot.Sandworm.setRegion("ru");
84
+ Riot.Sandworm.pvpnet({"show_regions":true,"show_links":true});
85
+ //--><!]]>
86
+ </script>
87
+
88
+
89
+
90
+
91
+
92
+ <div id="header">
93
+ <div id="header-content">
94
+ <a tite="" href="http://ru.leagueoflegends.com/ru/" id="lol-home-logo">League of Legends</a>
95
+ <div id="main-navigation">
96
+ <ul class="gs-container gs-table">
97
+ <li class="nav-dropdown-2-col nav-dropdown-deep">
98
+ <a href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/" title="">Информация об игре</a>
99
+ <div class="nav-dropdown-trigger">
100
+ <div class="nav-dropdown-container">
101
+ <div class="nav-dropdown-magic-bl"></div>
102
+ <div class="nav-dropdown-magic-br"></div>
103
+ <ul>
104
+ <li class="nav-dropdown-2nd-col">
105
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/">Введение</a>
106
+ <ul>
107
+ <li class="">
108
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/what-is-lol/">Что такое LoL?</a>
109
+ </li>
110
+ <li class="">
111
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/new-player-guide/">Руководство для новых игроков</a>
112
+ </li>
113
+ <li class="">
114
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/chat-commands/">Команды чата</a>
115
+ </li>
116
+ <li class="">
117
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/community-interaction/">Взаимодействие с игроками</a>
118
+ </li>
119
+ <li class="">
120
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/summoners-code/">Кодекс призывателя</a>
121
+ </li>
122
+ </ul>
123
+ </li>
124
+ <li class="nav-dropdown-2nd-col">
125
+ <a title="" href="https://signup.ru.leagueoflegends.com/ru/signup/download">Загрузка игры</a>
126
+ </li>
127
+ <li class="nav-dropdown-2nd-col">
128
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=95">Статус сервера</a>
129
+ </li>
130
+ <li class="">
131
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/champions/">Чемпионы</a>
132
+ </li>
133
+ <li class="">
134
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/items/">Предметы</a>
135
+ </li>
136
+ <li class="">
137
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/summoners/">Призыватели</a>
138
+ <ul>
139
+ <li class="">
140
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/summoners/spells/">Заклинания</a>
141
+ </li>
142
+ <li class="">
143
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/summoners/runes/">Руны</a>
144
+ </li>
145
+ <li class="">
146
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/summoners/masteries/">Таланты</a>
147
+ </li>
148
+ </ul>
149
+ </li>
150
+ <li class="">
151
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/game-modes/">Поля правосудия</a>
152
+ <ul>
153
+ <li class="">
154
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/game-modes/summoners-rift/">Ущелье призывателей</a>
155
+ </li>
156
+ <li class="">
157
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/game-modes/the-twisted-treeline/">Проклятый лес</a>
158
+ </li>
159
+ <li class="">
160
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/game-modes/howling-abyss/">Воющая бездна</a>
161
+ </li>
162
+ <li class="">
163
+ <a title="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/game-modes/the-crystal-scar/">Кристальный каньон</a>
164
+ </li>
165
+ </ul>
166
+ </li>
167
+ </ul>
168
+ </div>
169
+ </div>
170
+ </li>
171
+ <li class="nav-dropdown-deep">
172
+ <a href="http://ru.leagueoflegends.com/ru/news/" title="">Новости</a>
173
+ </li>
174
+ <li class="">
175
+ <a href="http://ru.leagueoflegends.com/ru/competitive/" title="">Соревнования</a>
176
+ </li>
177
+ <li class="">
178
+ <a href="http://forums.ru.leagueoflegends.com/board/" title="">Форумы</a>
179
+ <div class="nav-dropdown-trigger">
180
+ <div class="nav-dropdown-container">
181
+ <div class="nav-dropdown-magic-bl"></div>
182
+ <div class="nav-dropdown-magic-br"></div>
183
+ <ul>
184
+ <li class="">
185
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=58">Объявления</a>
186
+ </li>
187
+ <li class="">
188
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/devtracker.php?g=Riot">Сообщения от Riot</a>
189
+ </li>
190
+ <li class="">
191
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=55">Доминион</a>
192
+ </li>
193
+ <li class="">
194
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=53">Ущелье призывателей</a>
195
+ </li>
196
+ <li class="">
197
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=54">Проклятый лес</a>
198
+ </li>
199
+ <li class="">
200
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=56">Воющая бездна</a>
201
+ </li>
202
+ <li class="">
203
+ <a title="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=59">Общее обсуждение</a>
204
+ </li>
205
+ </ul>
206
+ </div>
207
+ </div>
208
+ </li>
209
+ <li class="">
210
+ <a href="http://ru.leagueoflegends.com/ru/community/" title="">Сообщество</a>
211
+ </li>
212
+ <li class="nav-dropdown-deep">
213
+ <a href="http://ru.leagueoflegends.com/ru/media/" title="">Медиа</a>
214
+ <div class="nav-dropdown-trigger">
215
+ <div class="nav-dropdown-container">
216
+ <div class="nav-dropdown-magic-bl"></div>
217
+ <div class="nav-dropdown-magic-br"></div>
218
+ <ul>
219
+ <li class="">
220
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/">Видео</a>
221
+ <ul>
222
+ <li class="">
223
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/patch-preview/">Обзоры обновлений</a>
224
+ </li>
225
+ <li class="">
226
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/champion-spotlight/">Обзоры чемпионов</a>
227
+ </li>
228
+ <li class="">
229
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/summoner-showcase/">Шоу призывателей</a>
230
+ </li>
231
+ <li class="">
232
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/creative-spotlight/">Творчество LoL</a>
233
+ </li>
234
+ <li class="">
235
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/video/fan-video/">Видео фанатов</a>
236
+ </li>
237
+ </ul>
238
+ </li>
239
+ <li class="">
240
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/art/">Арт</a>
241
+ <ul>
242
+ <li class="">
243
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/art/artwork/">Рисунки</a>
244
+ </li>
245
+ <li class="">
246
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/art/screenshot/">Скриншоты</a>
247
+ </li>
248
+ <li class="">
249
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/art/wallpaper/">Обои</a>
250
+ </li>
251
+ <li class="">
252
+ <a title="" href="http://ru.leagueoflegends.com/ru/media/art/fan-art/">Фан-арт</a>
253
+ </li>
254
+ </ul>
255
+ </li>
256
+ </ul>
257
+ </div>
258
+ </div>
259
+ </li>
260
+ </ul>
261
+ </div>
262
+ <a title="" href="http://signup.ru.leagueoflegends.com/ru" id="play-for-free" style="background-image:url(http://cdn.leagueoflegends.com/global-elements/0.0.22/images/play-cta/button-play-ru-ru.png); text-align: left; text-indent: -9999px; overflow: hidden; outline: none;">Начать игру</a>
263
+ </div>
264
+ </div>
265
+
266
+
267
+ <!-- BREADCRUMB -->
268
+ <div id="breadcrumbs">
269
+ <ol>
270
+ <li><a href="http://ru.leagueoflegends.com">Главная страница</a></li>
271
+ <li><a href="index.php">Форумы</a></li>
272
+
273
+ <li><a href="forumdisplay.php?f=67">Творчество поклонников игры</a></li>
274
+
275
+ <li><a href="forumdisplay.php?f=69">Литературное творчество</a></li>
276
+
277
+ </ol>
278
+ <h1>
279
+ Поэтический конкурс хайку
280
+ </h1>
281
+ </div>
282
+
283
+ <div class="section-wrapper section-wrapper-primary">
284
+ <div class="section-wrapper-top"></div>
285
+ <div class="section-wrapper-content">
286
+ <div class="section-wrapper-content-wrapper">
287
+
288
+ <!-- Silenced -->
289
+
290
+
291
+
292
+ <div class="clearfix">
293
+ <div class="clearfix">
294
+ <div class="float-left">
295
+ <h3>Поэтический конкурс хайку</h3>
296
+ </div>
297
+ <div class="float-right">
298
+
299
+ <div class="staff_thread">
300
+ <a href="showthread.php?p=108037#108037">
301
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/logo2.png" class="riot_logo" />
302
+ </a>
303
+ <div></div>
304
+ </div>
305
+ <div class="clear"></div>
306
+ <div style="height: 27px"></div>
307
+
308
+ </div>
309
+ </div >
310
+ <div class="clearfix showthread-top-buttons">
311
+ <div class="float-left ">
312
+
313
+ </div>
314
+ <div class="float-right
315
+
316
+ ">
317
+ <!-- TOP PAGINATION -->
318
+ <div class="pager">
319
+ <!-- class="results">Страница 14 из 86-->
320
+
321
+
322
+ <a href="showthread.php?t=13281&amp;page=13" title="Предыдущая страница - с 121 по 130 из 853"></a>
323
+
324
+
325
+ <a href="showthread.php?t=13281&amp;page=4" title="с 31 по 40 из 853"><!---10-->4</a><a href="showthread.php?t=13281&amp;page=10" title="с 91 по 100 из 853">10</a><a href="showthread.php?t=13281&amp;page=11" title="с 101 по 110 из 853">11</a><a href="showthread.php?t=13281&amp;page=12" title="с 111 по 120 из 853">12</a><a href="showthread.php?t=13281&amp;page=13" title="с 121 по 130 из 853">13</a><a class="active" href="#">14</a><a href="showthread.php?t=13281&amp;page=15" title="с 141 по 150 из 853">15</a><a href="showthread.php?t=13281&amp;page=16" title="с 151 по 160 из 853">16</a><a href="showthread.php?t=13281&amp;page=17" title="с 161 по 170 из 853">17</a><a href="showthread.php?t=13281&amp;page=18" title="с 171 по 180 из 853">18</a><a href="showthread.php?t=13281&amp;page=24" title="с 231 по 240 из 853"><!--+10-->24</a><a href="showthread.php?t=13281&amp;page=64" title="с 631 по 640 из 853"><!--+50-->64</a>
326
+
327
+
328
+ <span>...</span>
329
+ <a href="showthread.php?t=13281&amp;page=87" title="с 631 по 640 из 853">86</a>
330
+
331
+
332
+
333
+ <a rel="next" href="showthread.php?t=13281&amp;page=15" title="Следующая страница - с 141 по 150 из 853"></a>
334
+
335
+ </div>
336
+ </div>
337
+ </div>
338
+ </div>
339
+
340
+
341
+ <!-- Posts -->
342
+ <div id="edit108178" class="margin-top-15">
343
+ <div class="content-border sca_not_agree" id="post108178">
344
+ <div class="post_hidden_message white-stone">
345
+ <div class="white-stone-content">
346
+ Comment below rating threshold, click <a href="#">here</a> to show it.
347
+ </div>
348
+ </div>
349
+ <div class="white-stone post-row">
350
+ <div class="gs-container gs-no-gutter">
351
+ <div class="default-1-5">
352
+ <div class="post-col-left">
353
+ <p class="post-user"><font color="red">ThorSerpent</font></p>
354
+ <div class="content-border post-avatar">
355
+ <div class="white-stone">
356
+ <a class="avatar">
357
+
358
+ <img class="user_summoner_icon" src="image.php?u=3066&amp;dateline=1365763051" alt="Аватар для ThorSerpent" />
359
+
360
+ </a>
361
+ </div>
362
+ </div>
363
+
364
+
365
+
366
+
367
+
368
+
369
+
370
+
371
+
372
+
373
+
374
+
375
+ <p>
376
+ <font color="red"><strong>PR Manager</strong></font></b>
377
+
378
+ </p>
379
+ </div>
380
+ </div>
381
+ <div class="default-4-5">
382
+ <div class="post-col-right">
383
+ <div class="post-header padding-side-10 clearfix">
384
+ <!-- Post Date -->
385
+
386
+ <span>Сегодня, 17:49</span>
387
+
388
+
389
+
390
+
391
+
392
+
393
+ <!-- Riot Post -->
394
+
395
+ <a id="108178"></a>
396
+ <div class="float-right">
397
+ <span>
398
+
399
+ 3 из 3 сообщений от сотрудников Riot
400
+
401
+ </span>
402
+
403
+ <a href="showthread.php?p=108066#108066" title="Предыдущее сообщение от сотрудников Riot" od>
404
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/previous.png" class="previous_riot_post" />
405
+ </a>
406
+
407
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/logo2.png" class="riot_logo" />
408
+
409
+
410
+ </div>
411
+
412
+ </div>
413
+ <hr class="subtle-divider">
414
+
415
+ <div class="post-message">
416
+ <p>Журчанье воды<br />
417
+ Черно-белые тени<br />
418
+ Вновь на фонтане</p>
419
+
420
+
421
+
422
+ </div>
423
+ <hr class="subtle-divider">
424
+
425
+ <!-- Post Footer -->
426
+ <div class="post-footer padding-side-10 clearfix">
427
+ <!-- Post Ranking -->
428
+
429
+
430
+ <span class="post-rating padding-side-10 rating-negative">-2</span>
431
+
432
+
433
+
434
+ <div class="post-footer-buttons">
435
+
436
+
437
+
438
+
439
+
440
+ </div>
441
+ </div>
442
+ </div>
443
+ </div>
444
+ </div>
445
+ </div>
446
+ </div>
447
+ </div><div id="edit108179" class="margin-top-15">
448
+ <div class="content-border sca_not_agree" id="post108179">
449
+ <div class="post_hidden_message white-stone">
450
+ <div class="white-stone-content">
451
+ Comment below rating threshold, click <a href="#">here</a> to show it.
452
+ </div>
453
+ </div>
454
+ <div class="white-stone post-row">
455
+ <div class="gs-container gs-no-gutter">
456
+ <div class="default-1-5">
457
+ <div class="post-col-left">
458
+ <p class="post-user">jsawe</p>
459
+ <div class="content-border post-avatar">
460
+ <div class="white-stone">
461
+ <a class="avatar">
462
+
463
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
464
+
465
+ </a>
466
+ </div>
467
+ </div>
468
+
469
+
470
+
471
+
472
+
473
+
474
+
475
+
476
+
477
+
478
+
479
+
480
+ <p>
481
+ Junior Member
482
+
483
+ </p>
484
+ </div>
485
+ </div>
486
+ <div class="default-4-5">
487
+ <div class="post-col-right">
488
+ <div class="post-header padding-side-10 clearfix">
489
+ <!-- Post Date -->
490
+
491
+ <span>Сегодня, 17:49</span>
492
+
493
+
494
+
495
+
496
+
497
+
498
+ <!-- Riot Post -->
499
+
500
+ </div>
501
+ <hr class="subtle-divider">
502
+
503
+ <div class="post-message">
504
+ <p>Дариус стоит <br />
505
+ На топе нерушимый<br />
506
+ Он убил брата.<br />
507
+ <br />
508
+ <br />
509
+ <br />
510
+ Эзреаль встретил<br />
511
+ Минотавра буйного<br />
512
+ Это Алистар!<br />
513
+ <br />
514
+ Джинкс как ураган<br />
515
+ Разрушает все и везде<br />
516
+ Ее не поймать…</p>
517
+
518
+
519
+
520
+ </div>
521
+ <hr class="subtle-divider">
522
+
523
+ <!-- Post Footer -->
524
+ <div class="post-footer padding-side-10 clearfix">
525
+ <!-- Post Ranking -->
526
+
527
+
528
+ <span class="post-rating padding-side-10 rating-negative">-7</span>
529
+
530
+
531
+
532
+ <div class="post-footer-buttons">
533
+
534
+
535
+
536
+
537
+
538
+ </div>
539
+ </div>
540
+ </div>
541
+ </div>
542
+ </div>
543
+ </div>
544
+ </div>
545
+ </div><div id="edit108180" class="margin-top-15">
546
+ <div class="content-border sca_not_agree" id="post108180">
547
+ <div class="post_hidden_message white-stone">
548
+ <div class="white-stone-content">
549
+ Comment below rating threshold, click <a href="#">here</a> to show it.
550
+ </div>
551
+ </div>
552
+ <div class="white-stone post-row">
553
+ <div class="gs-container gs-no-gutter">
554
+ <div class="default-1-5">
555
+ <div class="post-col-left">
556
+ <p class="post-user">Revnor</p>
557
+ <div class="content-border post-avatar">
558
+ <div class="white-stone">
559
+ <a class="avatar">
560
+
561
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
562
+
563
+ </a>
564
+ </div>
565
+ </div>
566
+
567
+
568
+
569
+
570
+
571
+
572
+
573
+
574
+
575
+
576
+
577
+
578
+ <p>
579
+ Junior Member
580
+
581
+ </p>
582
+ </div>
583
+ </div>
584
+ <div class="default-4-5">
585
+ <div class="post-col-right">
586
+ <div class="post-header padding-side-10 clearfix">
587
+ <!-- Post Date -->
588
+
589
+ <span>Сегодня, 17:49</span>
590
+
591
+
592
+
593
+
594
+
595
+
596
+ <!-- Riot Post -->
597
+
598
+ </div>
599
+ <hr class="subtle-divider">
600
+
601
+ <div class="post-message">
602
+ <p>1)Гареном убит,<br />
603
+ Ургот-почетный палач.<br />
604
+ Но возрожден был.<br />
605
+ <br />
606
+ 2)Виктор силен,но<br />
607
+ Увы,не играют им.<br />
608
+ Печально,не так ли?<br />
609
+ <br />
610
+ 3)Кидаю фонарь,<br />
611
+ Чтобы спасти,но увы,<br />
612
+ Никто не нажал.</p>
613
+
614
+
615
+
616
+ </div>
617
+ <hr class="subtle-divider">
618
+
619
+ <!-- Post Footer -->
620
+ <div class="post-footer padding-side-10 clearfix">
621
+ <!-- Post Ranking -->
622
+
623
+
624
+ <span class="post-rating padding-side-10 rating-negative">-5</span>
625
+
626
+
627
+
628
+ <div class="post-footer-buttons">
629
+
630
+
631
+
632
+
633
+
634
+ </div>
635
+ </div>
636
+ </div>
637
+ </div>
638
+ </div>
639
+ </div>
640
+ </div>
641
+ </div><div id="edit108181" class="margin-top-15">
642
+ <div class="content-border sca_not_agree" id="post108181">
643
+ <div class="post_hidden_message white-stone">
644
+ <div class="white-stone-content">
645
+ Comment below rating threshold, click <a href="#">here</a> to show it.
646
+ </div>
647
+ </div>
648
+ <div class="white-stone post-row">
649
+ <div class="gs-container gs-no-gutter">
650
+ <div class="default-1-5">
651
+ <div class="post-col-left">
652
+ <p class="post-user">catan047</p>
653
+ <div class="content-border post-avatar">
654
+ <div class="white-stone">
655
+ <a class="avatar">
656
+
657
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
658
+
659
+ </a>
660
+ </div>
661
+ </div>
662
+
663
+
664
+
665
+
666
+
667
+
668
+
669
+
670
+
671
+
672
+
673
+
674
+ <p>
675
+ Junior Member
676
+
677
+ </p>
678
+ </div>
679
+ </div>
680
+ <div class="default-4-5">
681
+ <div class="post-col-right">
682
+ <div class="post-header padding-side-10 clearfix">
683
+ <!-- Post Date -->
684
+
685
+ <span>Сегодня, 17:49</span>
686
+
687
+
688
+
689
+
690
+
691
+
692
+ <!-- Riot Post -->
693
+
694
+ </div>
695
+ <hr class="subtle-divider">
696
+
697
+ <div class="post-message">
698
+ <p><i>темнота везде...<br />
699
+ На крыльях ночи летит<br />
700
+ к нам кошмарный сон.<br />
701
+ ...<br />
702
+ На землю упала,<br />
703
+ Обжигая все вокруг,<br />
704
+ большая бомба.<br />
705
+ ... <br />
706
+ Ключик на цепи<br />
707
+ Звенит с каждым ударом.<br />
708
+ души в фонаре...<br />
709
+ ...<br />
710
+ Ужасные звуки<br />
711
+ С кустов возле синего.<br />
712
+ Начнем с красного...<br />
713
+ ...<br />
714
+ Красный гадкий луч<br />
715
+ Пронзил небесную гладь...<br />
716
+ Пента удалась.</i></p>
717
+
718
+
719
+
720
+ </div>
721
+ <hr class="subtle-divider">
722
+
723
+ <!-- Post Footer -->
724
+ <div class="post-footer padding-side-10 clearfix">
725
+ <!-- Post Ranking -->
726
+
727
+
728
+ <span class="post-rating padding-side-10 rating-negative">-6</span>
729
+
730
+
731
+
732
+ <div class="post-footer-buttons">
733
+
734
+
735
+
736
+
737
+
738
+ </div>
739
+ </div>
740
+ </div>
741
+ </div>
742
+ </div>
743
+ </div>
744
+ </div>
745
+ </div><div id="edit108182" class="margin-top-15">
746
+ <div class="content-border sca_not_agree" id="post108182">
747
+ <div class="post_hidden_message white-stone">
748
+ <div class="white-stone-content">
749
+ Comment below rating threshold, click <a href="#">here</a> to show it.
750
+ </div>
751
+ </div>
752
+ <div class="white-stone post-row">
753
+ <div class="gs-container gs-no-gutter">
754
+ <div class="default-1-5">
755
+ <div class="post-col-left">
756
+ <p class="post-user">DeadsWolfs</p>
757
+ <div class="content-border post-avatar">
758
+ <div class="white-stone">
759
+ <a class="avatar">
760
+
761
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
762
+
763
+ </a>
764
+ </div>
765
+ </div>
766
+
767
+
768
+
769
+
770
+
771
+
772
+
773
+
774
+
775
+
776
+
777
+
778
+ <p>
779
+ Junior Member
780
+
781
+ </p>
782
+ </div>
783
+ </div>
784
+ <div class="default-4-5">
785
+ <div class="post-col-right">
786
+ <div class="post-header padding-side-10 clearfix">
787
+ <!-- Post Date -->
788
+
789
+ <span>Сегодня, 17:49</span>
790
+
791
+
792
+
793
+
794
+
795
+
796
+ <!-- Riot Post -->
797
+
798
+ </div>
799
+ <hr class="subtle-divider">
800
+
801
+ <div class="post-message">
802
+ <p>два воина безликих<br />
803
+ схлестнулись в бешеном бою<br />
804
+ но Тимо победил</p>
805
+
806
+
807
+
808
+ </div>
809
+ <hr class="subtle-divider">
810
+
811
+ <!-- Post Footer -->
812
+ <div class="post-footer padding-side-10 clearfix">
813
+ <!-- Post Ranking -->
814
+
815
+
816
+ <span class="post-rating padding-side-10 rating-negative">-5</span>
817
+
818
+
819
+
820
+ <div class="post-footer-buttons">
821
+
822
+
823
+
824
+
825
+
826
+ </div>
827
+ </div>
828
+ </div>
829
+ </div>
830
+ </div>
831
+ </div>
832
+ </div>
833
+ </div><div id="edit108183" class="margin-top-15">
834
+ <div class="content-border sca_not_agree" id="post108183">
835
+ <div class="post_hidden_message white-stone">
836
+ <div class="white-stone-content">
837
+ Comment below rating threshold, click <a href="#">here</a> to show it.
838
+ </div>
839
+ </div>
840
+ <div class="white-stone post-row">
841
+ <div class="gs-container gs-no-gutter">
842
+ <div class="default-1-5">
843
+ <div class="post-col-left">
844
+ <p class="post-user">ArchVendetta</p>
845
+ <div class="content-border post-avatar">
846
+ <div class="white-stone">
847
+ <a class="avatar">
848
+
849
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
850
+
851
+ </a>
852
+ </div>
853
+ </div>
854
+
855
+
856
+
857
+
858
+
859
+
860
+
861
+
862
+
863
+
864
+
865
+
866
+ <p>
867
+ Junior Member
868
+
869
+ </p>
870
+ </div>
871
+ </div>
872
+ <div class="default-4-5">
873
+ <div class="post-col-right">
874
+ <div class="post-header padding-side-10 clearfix">
875
+ <!-- Post Date -->
876
+
877
+ <span>Сегодня, 17:49</span>
878
+
879
+
880
+
881
+
882
+
883
+
884
+ <!-- Riot Post -->
885
+
886
+ </div>
887
+ <hr class="subtle-divider">
888
+
889
+ <div class="post-message">
890
+ <p>Топор могучий<br />
891
+ Ноксианский палач<br />
892
+ Не ведал страха</p>
893
+
894
+
895
+
896
+ </div>
897
+ <hr class="subtle-divider">
898
+
899
+ <!-- Post Footer -->
900
+ <div class="post-footer padding-side-10 clearfix">
901
+ <!-- Post Ranking -->
902
+
903
+
904
+ <span class="post-rating padding-side-10 rating-negative">-6</span>
905
+
906
+
907
+
908
+ <div class="post-footer-buttons">
909
+
910
+
911
+
912
+
913
+
914
+ </div>
915
+ </div>
916
+ </div>
917
+ </div>
918
+ </div>
919
+ </div>
920
+ </div>
921
+ </div><div id="edit108184" class="margin-top-15">
922
+ <div class="content-border sca_not_agree" id="post108184">
923
+ <div class="post_hidden_message white-stone">
924
+ <div class="white-stone-content">
925
+ Comment below rating threshold, click <a href="#">here</a> to show it.
926
+ </div>
927
+ </div>
928
+ <div class="white-stone post-row">
929
+ <div class="gs-container gs-no-gutter">
930
+ <div class="default-1-5">
931
+ <div class="post-col-left">
932
+ <p class="post-user">Jack W0lf</p>
933
+ <div class="content-border post-avatar">
934
+ <div class="white-stone">
935
+ <a class="avatar">
936
+
937
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
938
+
939
+ </a>
940
+ </div>
941
+ </div>
942
+
943
+
944
+
945
+
946
+
947
+
948
+
949
+
950
+
951
+
952
+
953
+
954
+ <p>
955
+ Junior Member
956
+
957
+ </p>
958
+ </div>
959
+ </div>
960
+ <div class="default-4-5">
961
+ <div class="post-col-right">
962
+ <div class="post-header padding-side-10 clearfix">
963
+ <!-- Post Date -->
964
+
965
+ <span>Сегодня, 17:50</span>
966
+
967
+
968
+
969
+
970
+
971
+
972
+ <!-- Riot Post -->
973
+
974
+ </div>
975
+ <hr class="subtle-divider">
976
+
977
+ <div class="post-message">
978
+ <p>1.<br />
979
+ <br />
980
+ Замерло сердце-<br />
981
+ Враг в кустах.<br />
982
+ Джанглер моя роль.<br />
983
+ <br />
984
+ 2.<br />
985
+ <br />
986
+ Тотемы стоят.<br />
987
+ Шум воды.<br />
988
+ Бегу за Вай в лес.</p>
989
+
990
+
991
+
992
+ </div>
993
+ <hr class="subtle-divider">
994
+
995
+ <!-- Post Footer -->
996
+ <div class="post-footer padding-side-10 clearfix">
997
+ <!-- Post Ranking -->
998
+
999
+
1000
+ <span class="post-rating padding-side-10 rating-negative">-6</span>
1001
+
1002
+
1003
+
1004
+ <div class="post-footer-buttons">
1005
+
1006
+
1007
+
1008
+
1009
+
1010
+ </div>
1011
+ </div>
1012
+ </div>
1013
+ </div>
1014
+ </div>
1015
+ </div>
1016
+ </div>
1017
+ </div><div id="edit108185" class="margin-top-15">
1018
+ <div class="content-border sca_not_agree" id="post108185">
1019
+ <div class="post_hidden_message white-stone">
1020
+ <div class="white-stone-content">
1021
+ Comment below rating threshold, click <a href="#">here</a> to show it.
1022
+ </div>
1023
+ </div>
1024
+ <div class="white-stone post-row">
1025
+ <div class="gs-container gs-no-gutter">
1026
+ <div class="default-1-5">
1027
+ <div class="post-col-left">
1028
+ <p class="post-user">Tommy Oblivion</p>
1029
+ <div class="content-border post-avatar">
1030
+ <div class="white-stone">
1031
+ <a class="avatar">
1032
+
1033
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
1034
+
1035
+ </a>
1036
+ </div>
1037
+ </div>
1038
+
1039
+
1040
+
1041
+
1042
+
1043
+
1044
+
1045
+
1046
+
1047
+ <img src="http://cdn.leagueoflegends.com/apollo/badges/s3platinum.png" title="Platinum" />
1048
+
1049
+
1050
+
1051
+
1052
+ <p>
1053
+ Junior Member
1054
+
1055
+ </p>
1056
+ </div>
1057
+ </div>
1058
+ <div class="default-4-5">
1059
+ <div class="post-col-right">
1060
+ <div class="post-header padding-side-10 clearfix">
1061
+ <!-- Post Date -->
1062
+
1063
+ <span>Сегодня, 17:50</span>
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+ <!-- Riot Post -->
1071
+
1072
+ </div>
1073
+ <hr class="subtle-divider">
1074
+
1075
+ <div class="post-message">
1076
+ <p>Всем игрокам за желтого робота.<br />
1077
+ <br />
1078
+ <br />
1079
+ <i>В кустах блестит металл<br />
1080
+ И искрится ток<br />
1081
+ Человечеству конец</i></p>
1082
+
1083
+
1084
+
1085
+ </div>
1086
+ <hr class="subtle-divider">
1087
+
1088
+ <!-- Post Footer -->
1089
+ <div class="post-footer padding-side-10 clearfix">
1090
+ <!-- Post Ranking -->
1091
+
1092
+
1093
+ <span class="post-rating padding-side-10 rating-negative">-4</span>
1094
+
1095
+
1096
+
1097
+ <div class="post-footer-buttons">
1098
+
1099
+
1100
+
1101
+
1102
+
1103
+ </div>
1104
+ </div>
1105
+ </div>
1106
+ </div>
1107
+ </div>
1108
+ </div>
1109
+ </div>
1110
+ </div><div id="edit108186" class="margin-top-15">
1111
+ <div class="content-border sca_not_agree" id="post108186">
1112
+ <div class="post_hidden_message white-stone">
1113
+ <div class="white-stone-content">
1114
+ Comment below rating threshold, click <a href="#">here</a> to show it.
1115
+ </div>
1116
+ </div>
1117
+ <div class="white-stone post-row">
1118
+ <div class="gs-container gs-no-gutter">
1119
+ <div class="default-1-5">
1120
+ <div class="post-col-left">
1121
+ <p class="post-user">KuroGod</p>
1122
+ <div class="content-border post-avatar">
1123
+ <div class="white-stone">
1124
+ <a class="avatar">
1125
+
1126
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
1127
+
1128
+ </a>
1129
+ </div>
1130
+ </div>
1131
+
1132
+
1133
+
1134
+
1135
+
1136
+
1137
+
1138
+
1139
+
1140
+
1141
+
1142
+
1143
+ <p>
1144
+ Junior Member
1145
+
1146
+ </p>
1147
+ </div>
1148
+ </div>
1149
+ <div class="default-4-5">
1150
+ <div class="post-col-right">
1151
+ <div class="post-header padding-side-10 clearfix">
1152
+ <!-- Post Date -->
1153
+
1154
+ <span>Сегодня, 17:51</span>
1155
+
1156
+
1157
+
1158
+
1159
+
1160
+
1161
+ <!-- Riot Post -->
1162
+
1163
+ </div>
1164
+ <hr class="subtle-divider">
1165
+
1166
+ <div class="post-message">
1167
+ <p>Мы снова живем...<br />
1168
+ Ваша участь, прахом стать<br />
1169
+ Муки вечны вам.</p>
1170
+
1171
+
1172
+
1173
+ </div>
1174
+ <hr class="subtle-divider">
1175
+
1176
+ <!-- Post Footer -->
1177
+ <div class="post-footer padding-side-10 clearfix">
1178
+ <!-- Post Ranking -->
1179
+
1180
+
1181
+ <span class="post-rating padding-side-10 rating-negative">-5</span>
1182
+
1183
+
1184
+
1185
+ <div class="post-footer-buttons">
1186
+
1187
+
1188
+
1189
+
1190
+
1191
+ </div>
1192
+ </div>
1193
+ </div>
1194
+ </div>
1195
+ </div>
1196
+ </div>
1197
+ </div>
1198
+ </div><div id="edit108187" class="margin-top-15">
1199
+ <div class="content-border sca_not_agree" id="post108187">
1200
+ <div class="post_hidden_message white-stone">
1201
+ <div class="white-stone-content">
1202
+ Comment below rating threshold, click <a href="#">here</a> to show it.
1203
+ </div>
1204
+ </div>
1205
+ <div class="white-stone post-row">
1206
+ <div class="gs-container gs-no-gutter">
1207
+ <div class="default-1-5">
1208
+ <div class="post-col-left">
1209
+ <p class="post-user">scorp13</p>
1210
+ <div class="content-border post-avatar">
1211
+ <div class="white-stone">
1212
+ <a class="avatar">
1213
+
1214
+ <img class="user_summoner_icon" src="lol_theme/img/unknown_icon.jpg" />
1215
+
1216
+ </a>
1217
+ </div>
1218
+ </div>
1219
+
1220
+
1221
+
1222
+
1223
+
1224
+
1225
+
1226
+
1227
+
1228
+
1229
+
1230
+
1231
+ <p>
1232
+ Junior Member
1233
+
1234
+ </p>
1235
+ </div>
1236
+ </div>
1237
+ <div class="default-4-5">
1238
+ <div class="post-col-right">
1239
+ <div class="post-header padding-side-10 clearfix">
1240
+ <!-- Post Date -->
1241
+
1242
+ <span>Сегодня, 17:51</span>
1243
+
1244
+
1245
+
1246
+
1247
+
1248
+
1249
+ <!-- Riot Post -->
1250
+
1251
+ </div>
1252
+ <hr class="subtle-divider">
1253
+
1254
+ <div class="post-message">
1255
+ <p><i>Стою на топе,<br />
1256
+ Почти убил врага я,<br />
1257
+ Картус стилит фраг.</i></p>
1258
+
1259
+
1260
+
1261
+ </div>
1262
+ <hr class="subtle-divider">
1263
+
1264
+ <!-- Post Footer -->
1265
+ <div class="post-footer padding-side-10 clearfix">
1266
+ <!-- Post Ranking -->
1267
+
1268
+
1269
+ <span class="post-rating padding-side-10 rating-negative">-7</span>
1270
+
1271
+
1272
+
1273
+ <div class="post-footer-buttons">
1274
+
1275
+
1276
+
1277
+
1278
+
1279
+ </div>
1280
+ </div>
1281
+ </div>
1282
+ </div>
1283
+ </div>
1284
+ </div>
1285
+ </div>
1286
+ </div>
1287
+ <!--div id="lastpost" class="post_separator"></div-->
1288
+
1289
+ <div class="margin-top-15 clearfix">
1290
+ <div class="float-left">
1291
+
1292
+ </div>
1293
+ <div class="float-right"></div>
1294
+ <!-- BOTTOM PAGINATION -->
1295
+ <div class="pager">
1296
+ <!-- class="results">Страница 14 из 86-->
1297
+
1298
+
1299
+ <a href="showthread.php?t=13281&amp;page=13" title="Предыдущая страница - с 121 по 130 из 853"></a>
1300
+
1301
+
1302
+ <a href="showthread.php?t=13281&amp;page=4" title="с 31 по 40 из 853"><!---10-->4</a><a href="showthread.php?t=13281&amp;page=10" title="с 91 по 100 из 853">10</a><a href="showthread.php?t=13281&amp;page=11" title="с 101 по 110 из 853">11</a><a href="showthread.php?t=13281&amp;page=12" title="с 111 по 120 из 853">12</a><a href="showthread.php?t=13281&amp;page=13" title="с 121 по 130 из 853">13</a><a class="active" href="#">14</a><a href="showthread.php?t=13281&amp;page=15" title="с 141 по 150 из 853">15</a><a href="showthread.php?t=13281&amp;page=16" title="с 151 по 160 из 853">16</a><a href="showthread.php?t=13281&amp;page=17" title="с 161 по 170 из 853">17</a><a href="showthread.php?t=13281&amp;page=18" title="с 171 по 180 из 853">18</a><a href="showthread.php?t=13281&amp;page=24" title="с 231 по 240 из 853"><!--+10-->24</a><a href="showthread.php?t=13281&amp;page=64" title="с 631 по 640 из 853"><!--+50-->64</a>
1303
+
1304
+
1305
+ <span>...</span>
1306
+ <a href="showthread.php?t=13281&amp;page=87" title="с 631 по 640 из 853">86</a>
1307
+
1308
+
1309
+
1310
+ <a rel="next" href="showthread.php?t=13281&amp;page=15" title="Следующая страница - с 141 по 150 из 853"></a>
1311
+
1312
+ </div>
1313
+ </div>
1314
+
1315
+
1316
+
1317
+
1318
+
1319
+ <!-- QUICK REPLY JS -->
1320
+
1321
+
1322
+ <!-- QUICK REPLY -->
1323
+
1324
+
1325
+ <!-- NEXT / PREVIOUS LINKS -->
1326
+
1327
+ <div class="margin-top-15 center thread-page-links">
1328
+ <strong>&laquo;</strong>
1329
+ <a href="showthread.php?t=13281&amp;goto=nextoldest" rel="nofollow">Предыдущая тема</a>
1330
+ |
1331
+ <a href="showthread.php?t=13281&amp;goto=nextnewest" rel="nofollow">Следующая тема</a>
1332
+ <strong>&raquo;</strong>
1333
+ </div>
1334
+
1335
+ <!-- / next / previous links -->
1336
+ </div>
1337
+ </div>
1338
+ <div class="section-wrapper-bottom"></div>
1339
+ </div>
1340
+
1341
+ <!-- FOOTER -->
1342
+ <script type="text/javascript">
1343
+ <!--
1344
+ // Main vBulletin Javascript Initialization
1345
+ vBulletin_init();
1346
+ // -->
1347
+ </script>
1348
+ <div id="footer">
1349
+ <div id="footer-content">
1350
+ <ul id="footer-nav" class="simple-menu">
1351
+ <li><a title="" class="" href="http://gameinfo.ru.leagueoflegends.com/ru/game-info/get-started/what-is-lol/">Об игре League Of Legends</a></li>
1352
+ <li><a title="" class="" href="http://www.jinx.com/shop/coll/leagueoflegends/?lang=en-US">Сувениры</a></li>
1353
+ <li><a title="" class="" href="http://leagueoflegends.ru-Surveyru2.sgizmo.com/s3/">Помогите нам стать лучше</a></li>
1354
+ <li><a title="" class="" href="http://forums.ru.leagueoflegends.com/board/forumdisplay.php?f=95">Статус сервера</a></li>
1355
+ <li><a title="" class="" href="http://support.leagueoflegends.com/">Поддержка</a></li>
1356
+ </ul>
1357
+ <div class="gs-container vertical-gutter">
1358
+ <div class="default-1-5">
1359
+ <div id="riot-social">
1360
+ <a class="riot-logo" href="http://www.riotgames.com/">Riot Games</a>
1361
+ <ul class="social-links">
1362
+ <li>
1363
+ <a class="youtube" title="" href="http://www.youtube.com/user/RiotGamesRU" >
1364
+ YouTube.com
1365
+ </a>
1366
+ </li>
1367
+ <li>
1368
+ <a class="twitter" title="" href="http://twitter.com/LoL_CIS" >
1369
+ Twitter.com
1370
+ </a>
1371
+ </li>
1372
+ <li>
1373
+ <a class="facebook" title="" href="http://www.facebook.com/LeagueOfLegendsRU" >
1374
+ Facebook.com
1375
+ </a>
1376
+ </li>
1377
+ <li>
1378
+ <a class="" title="" href="http://vk.com/leagueoflegends" style="background-image:url(http://cdn.leagueoflegends.com/global-elements/0.0.22/images/vk.png);background-position:0 0;">
1379
+ vkontakte.ru
1380
+ </a>
1381
+ </li>
1382
+ </ul>
1383
+ </div>
1384
+ </div>
1385
+ <div class="default-3-5">
1386
+ <a class="btn-large btn-large-primary" tite="" href="http://signup.ru.leagueoflegends.com/ru" id="footer-play-for-free">Начать игру</a>
1387
+ <p>&copy; 2013 Riot Games, Inc. Все права защищены. Riot Games, League of Legends и PvP.net являются торговыми знаками или зарегистрированными торговыми знаками, принадлежащими Riot Games, Inc. Riot Games, Ltd., P.O. Box 11989, Dublin 2, IRELAND</p>
1388
+ <ul id="footer-sub-nav" class="simple-menu">
1389
+ <li><a title="" class="" href="http://ru.leagueoflegends.com/ru/legal/eula">Cоглашение с конечным пользователем</a></li>
1390
+ <li><a title="" class="" href="http://ru.leagueoflegends.com/ru/legal/privacy">Политика конфиденциальности</a></li>
1391
+ <li><a title="" class="" href="http://ru.leagueoflegends.com/ru/legal/termsofuse">Условия использования</a></li>
1392
+ </ul>
1393
+ </div>
1394
+ <div class="default-1-5">
1395
+ <div id="pvp-net-ad">
1396
+ <a class="pvp-net" href="http://pvp.net" title="">PVP.net</a>
1397
+ <ul class="pvpnet-links simple-menu">
1398
+ <li><a class="" title="" href="http://signup.ru.leagueoflegends.com/ru">Зарегистрироваться</a></li>
1399
+ <li><a class="" title="" href="http://support.leagueoflegends.com/home">Поддержка</a></li>
1400
+ </ul>
1401
+ </div>
1402
+ </div>
1403
+ </div>
1404
+ <div class="ad-bar lol-sponsors gs-container gs-half-gutter vertical-gutter content-center default-2-col">
1405
+ <div>
1406
+ <a class="alienware" href="http://www.alienware.com/Landings/laptops.aspx?c=us&l=en&s=dhs&ST=alienware%20%28exact%29&dgc=ST&cid=42319&lid=1082909&acd=64011,8,0,78307114,751003123,1285354600,,15511657,4924320670&redirect=1">
1407
+ <img src="http://cdn.leagueoflegends.com/global-elements/0.0.22/images/alienware.png" title="Alienware"/>
1408
+ </a>
1409
+ </div>
1410
+ <div>
1411
+ <a class="" href="http://ru.leagueoflegends.com/ru/legal/eula">
1412
+ <img src="http://cdn.leagueoflegends.com/global-elements/0.0.22/images/ru-rating.jpg" title="Рейтинг 12+"/>
1413
+ </a>
1414
+ </div>
1415
+ </div>
1416
+ </div>
1417
+ </div>
1418
+
1419
+
1420
+
1421
+
1422
+ <!-- Google Tag Manager -->
1423
+ <noscript><iframe src="//www.googletagmanager.com/ns.html?id=GTM-N98J"
1424
+ height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
1425
+ <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
1426
+ new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
1427
+ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
1428
+ '//www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
1429
+ })(window,document,'script','dataLayer','GTM-N98J');</script>
1430
+ <!-- End Google Tag Manager -->
1431
+
1432
+
1433
+ <script type="text/javascript">s_account="riotgamesuniverse,riotgamesleagueoflegends";</script>
1434
+ <script type="text/javascript" src="http://cdn.leagueoflegends.com/omniture/0.0.2/js/omniture_code.js"></script>
1435
+
1436
+ <script type="text/javascript">
1437
+ s.channel="forums";
1438
+ s.charSet="UTF-8";
1439
+ s.pageName="lol2:ru:ru:forums:Литературное творчество:Поэтический конкурс хайку";
1440
+ s.prop1="lol2:ru";
1441
+ s.prop2="lol2:ru:ru";
1442
+ s.prop3="lol2:ru:ru:forums";
1443
+ s.prop4="lol2:ru:ru:forums:Литературное творчество";
1444
+ s.prop5="lol2:ru:ru:forums:Литературное творчество:Поэтический конкурс хайку";
1445
+ s.prop6="ru";
1446
+ s.eVar21="+1";
1447
+ s.events="event21";
1448
+
1449
+ var s_code=s.t();if(s_code)document.write(s_code)
1450
+ </script>
1451
+
1452
+ <script type="text/javascript">
1453
+ if(navigator.appVersion.indexOf('MSIE')>=0)document.write(unescape('%3C')+'\!-'+'-')
1454
+ </script>
1455
+
1456
+ <noscript>
1457
+ <a href="http://www.omniture.com" title="Web Analytics"><img src="http://examplecom.112.2O7.net/b/ss/examplecom/1/H.13--NS/0/4654065"
1458
+ height="1" width="1" border="0" alt="" /></a>
1459
+ </noscript>
1460
+
1461
+ <!-- Scripts -->
1462
+ <script src="/board/riot-assets/js/reskin-utils.js"></script>
1463
+ </body>
1464
+ </html>
vendor/paquettg/php-html-parser/tests/files/horrible.html ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html>
2
+ <head>
3
+ <title>МАРнет</title>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
5
+ <style type="text/css">
6
+ .meni {
7
+ font-size: 14px;
8
+ color: #000000;}
9
+ .meni:hover{
10
+ font-size: 14px;
11
+ color: #000000;
12
+ text-decoration:none;
13
+ background-color: #DDDDDD}
14
+
15
+ .meni1 {
16
+ font-size: 20px;
17
+ color: #000000;}
18
+ .meni1:hover{
19
+ font-size: 20px;
20
+ color: #000000;
21
+ text-decoration:none;
22
+ background-color: #DDDDDD;}
23
+
24
+ .tr{
25
+ COLOR: #FF0000;
26
+ TEXT-DECORATION:none;
27
+ font-size:11pt;
28
+ }
29
+ .tr:hover {
30
+ COLOR: #000000;
31
+ text-decoration:none;
32
+ font-size:11pt;
33
+ }
34
+ .do{
35
+ COLOR: #000000;
36
+ TEXT-DECORATION:none;
37
+ font-size:12pt;
38
+ }
39
+ .do:hover {
40
+ COLOR: #000000;
41
+ text-decoration:underline;
42
+ font-size:12pt;
43
+ }
44
+ .gr{
45
+ font-size: 13px;
46
+ color: #CCCCCC;
47
+ TEXT-DECORATION:none;
48
+ }
49
+ .gr:hover {
50
+ font-size: 13px;
51
+ COLOR: #000000;
52
+ text-decoration:none;
53
+ }
54
+ .ddd {
55
+ COLOR:#FF0000;
56
+ }
57
+ </style>
58
+
59
+ <script language="JavaScript" type="text/JavaScript">
60
+ <!--
61
+ function MM_jumpMenu(targ,selObj,restore){ //v3.0
62
+ eval(targ+".location='"+selObj.options[selObj.selectedIndex].value+"'");
63
+ if (restore) selObj.selectedIndex=0;
64
+ }
65
+ //-->
66
+ </script>
67
+
68
+ </head>
69
+
70
+ <body bgcolor="#FFFFFF" link="#000000" vlink="#000000" alink="#000000" ftmargin="5" topmargin="5" marginwidth="0" marginheight="0">
71
+ <!--<table width="750" border="0" cellspacing="0" cellpadding="0" align="center">
72
+ <tr align="center" valign="top">
73
+ <td colspan="4" height="130">
74
+ <table>
75
+ <tbody>
76
+ <tr>
77
+ <td rowspan="2" height="130" width="163"><img src="_sliki/mk.jpg" height="130" width="161"></td>
78
+ <td height="75" width="326">
79
+ <div align="left"><img src="_sliki/marnet.jpg" height="70" width="184"></div>
80
+ </td>
81
+ <td align="right" height="75" valign="top" width="261">
82
+ </td>
83
+ </tr>
84
+ <tr>
85
+ <td colspan="2" height="52"><img src="_sliki/regis.jpg" height="18" width="467"></td>
86
+ </tr>
87
+ </tbody>
88
+ </table
89
+ </td>
90
+ </tr>
91
+ <tr>
92
+ <td height="117" colspan="4" align="center" valign="top" class="meni">
93
+ <table width="100%" border="0" cellspacing="1" cellpadding="0">
94
+ <tr >
95
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
96
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
97
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
98
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
99
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
100
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
101
+ </tr>
102
+ <tr>
103
+ <td width="15%" ><div align="center"><a href="index.php" class="meni">mk домен</a></div></td>
104
+ <td width="15%"><div align="center"><a href="postapka.php" class="meni">регистрација</a>
105
+ </div></td>
106
+ <td width="15%" ><div align="center"><a href="cenovnik.php" class="meni">ценовник</a></div></td>
107
+ <td width="15%"><div align="center"><a href="oper.php" class="meni">операција со домени</a> </div></td>
108
+ <td width="15%" > <div align="center"><a href="izvesti.php" class="meni">известувања</a>
109
+ <img src="_sliki/updated.gif" border="0" alt="����� �����������" title="����� �����������!!!">
110
+ </div></td>
111
+ <td width="15%" > <div align="center"><a href="registar.php" class="meni">регистар</a></div></td>
112
+ </tr>
113
+ <tr>
114
+ <td colspan="6">&nbsp </td>
115
+ </tr>
116
+ <tr >
117
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
118
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
119
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
120
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
121
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
122
+ <td width="15%" background="_sliki/hori_rulefill_3x1.gif"></td>
123
+ </tr>
124
+ </table>-->
125
+
126
+ <p style="text-align: center;">
127
+
128
+ <a href="registar.php?bukva=NUM" class="meni1">0-9</a> <a href="registar.php?bukva=A" class="meni1">A</a>
129
+ <a href="registar.php?bukva=B" class="meni1">B</a> <a href="registar.php?bukva=C" class="meni1">C</a>
130
+ <a href="registar.php?bukva=D" class="meni1">D</a> <a href="registar.php?bukva=E" class="meni1">E</a>
131
+ <a href="registar.php?bukva=F" class="meni1">F</a> <a href="registar.php?bukva=G" class="meni1">G</a>
132
+ <a href="registar.php?bukva=H" class="meni1">H</a> <a href="registar.php?bukva=I" class="meni1">I</a>
133
+ <a href="registar.php?bukva=J" class="meni1">J</a> <a href="registar.php?bukva=K" class="meni1">K</a>
134
+ <a href="registar.php?bukva=L" class="meni1">L</a> <a href="registar.php?bukva=M" class="meni1">M</a>
135
+ <a href="registar.php?bukva=N" class="meni1">N</a> <a href="registar.php?bukva=O" class="meni1">O</a>
136
+ <a href="registar.php?bukva=P" class="meni1">P</a> <a href="registar.php?bukva=Q" class="meni1">Q</a>
137
+ <a href="registar.php?bukva=R" class="meni1">R</a> <a href="registar.php?bukva=S" class="meni1">S</a>
138
+ <a href="registar.php?bukva=T" class="meni1">T</a> <a href="registar.php?bukva=U" class="meni1">U</a>
139
+ <a href="registar.php?bukva=V" class="meni1">V</a> <a href="registar.php?bukva=X" class="meni1">X</a> <a href="registar.php?bukva=Y" class="meni1">Y</a>
140
+ <a href="registar.php?bukva=W" class="meni1">W</a> <a href="registar.php?bukva=Z" class="meni1">Z</a>
141
+
142
+ </p>
143
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
144
+ <tr >
145
+ <td width="15%" background="hori_rulefill_3x1.gif"></td>
146
+ <td width="15%" background="hori_rulefill_3x1.gif"></td>
147
+ <td width="15%" background="hori_rulefill_3x1.gif"></td>
148
+ <td width="15%" background="hori_rulefill_3x1.gif"></td>
149
+ <td width="15%" background="hori_rulefill_3x1.gif"></td>
150
+ </tr>
151
+ </table>
152
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
153
+ <tr>
154
+ <td align="center" valign="top">
155
+
156
+ <form name="form1" method="post" action="">
157
+ ���������� �� �������:
158
+ <input type="text" name="dom" size="35" maxlength="45">
159
+ <input type="submit" tabindex="0" name="submit" value="����������">
160
+ </form>
161
+ <br>
162
+ <hr><table width="100%" border="1" cellspacing="0" cellpadding="0">
163
+ <tr valign="top">
164
+ <td> <div align="center"><b><font size="4"> ������ ������������ ������: </br><a href="http://reg.marnet.net.mk/registar.php?dom=marnet.org.mk">marnet.org.mk</a></br><a href="http://reg.marnet.net.mk/registar.php?dom=marnet.edu.mk">marnet.edu.mk</a></br><a href="http://reg.marnet.net.mk/registar.php?dom=marnet.com.mk">marnet.com.mk</a></br><a href="http://reg.marnet.net.mk/registar.php?dom=marnet.mk">marnet.mk</a></br></div>
165
+ </td>
166
+ <td>
167
+ <table width="100%" border="0" cellspacing="0" cellpadding="0">
168
+ <tr bgcolor="#F4E8D8">
169
+ <td colspan="2">
170
+ <div align="center"><b><font size="4">�������� �� �������: marnet.mk</font> <i>[ ����� ��:12928 ]</i></div>
171
+ </td>
172
+ </tr>
173
+ <tr>
174
+ <td colspan="2">
175
+ <blockquote>���� �� ��� � ������� �������������: 22-05-2014 </blockquote>
176
+ </td>
177
+ </tr>
178
+ <tr>
179
+ <td width="50%">
180
+ <blockquote>
181
+ <p>���� �� ����������� �� �������:</p>
182
+ </blockquote>
183
+ </td>
184
+ <td width="50%">22-05-2008</td>
185
+ </tr>
186
+ <tr>
187
+ <td>
188
+ <blockquote>
189
+ <p>����� ��� �� ������������:</p>
190
+ </blockquote>
191
+ </td>
192
+ <td>���������� ��������� ������������ ����� �����</td>
193
+ </tr>
194
+ <tr>
195
+ <td>
196
+ <blockquote>
197
+ <p>������ �� ������������:</p>
198
+ </blockquote>
199
+ </td>
200
+ <td>��. ������� ����������� ������ ��.17 ���ϣ�</td>
201
+ </tr>
202
+ <tr>
203
+ <td>
204
+ <blockquote>
205
+ <p>��� �� ������������:</p>
206
+ </blockquote>
207
+ </td>
208
+ <td>4080011519278</td>
209
+ </tr>
210
+ <tr>
211
+ <td>
212
+ <blockquote>
213
+ <p>�������� �� ������������:</p>
214
+ </blockquote>
215
+ </td>
216
+ <td>02/3256-561</td>
217
+ </tr>
218
+ <tr>
219
+ <td>&nbsp;</td>
220
+ <td>&nbsp;</td>
221
+ </tr>
222
+ <tr bgcolor="#F4E8D8">
223
+ <td colspan="2"><b><font size="4">��������������� �������</font></b></td>
224
+ </tr>
225
+ <tr>
226
+ <td>
227
+ <blockquote>
228
+ <p>���:</p>
229
+ </blockquote>
230
+ </td>
231
+ <td>���� �����������</td>
232
+ </tr>
233
+ <tr>
234
+ <td>
235
+ <blockquote>
236
+ <p>e-mail:</p>
237
+ </blockquote>
238
+ </td>
239
+ <td>domains@marnet.net.mk</td>
240
+ </tr>
241
+ <tr>
242
+ <td>
243
+ <blockquote>
244
+ <p>�������:</p>
245
+ </blockquote>
246
+ </td>
247
+ <td>//</td>
248
+ </tr>
249
+ <tr bgcolor="#F4E8D8">
250
+ <td colspan="2"><b><font size="4">�������� �������</font></b></td>
251
+ </tr>
252
+ <tr>
253
+ <td>
254
+ <blockquote>
255
+ <p>���:</p>
256
+ </blockquote>
257
+ </td>
258
+ <td>���� �����������</td>
259
+ </tr>
260
+ <tr>
261
+ <td>
262
+ <blockquote>
263
+ <p>e-mail:</p>
264
+ </blockquote>
265
+ </td>
266
+ <td>domains@marnet.net.mk</td>
267
+ </tr>
268
+ <tr>
269
+ <td>
270
+ <blockquote>
271
+ <p>�������:</p>
272
+ </blockquote>
273
+ </td>
274
+ <td>//</td>
275
+ </tr>
276
+ <tr bgcolor="#F4E8D8">
277
+ <td colspan="2"><b><font size="4">������� �����������</font></b></td>
278
+ </tr>
279
+ <tr>
280
+ <td><div align="center">���</div></td>
281
+ <td><div align="center">IP</div></td>
282
+ </tr>
283
+ <tr align="center">
284
+ <td>nsg.mio.gov.mk</td>
285
+ <td>80.77.151.251</td>
286
+ </tr>
287
+ <tr align="center">
288
+ <td>kitka.marnet.net.mk</td>
289
+ <td>194.149.131.2</td>
290
+ </tr>
291
+ <table width="100%" border="0" cellpadding="0" cellspacing="0">
292
+ <tr bgcolor="#F4E8D8">
293
+ <td colspan="5">
294
+ <strong><font size="4", color="\#000000">
295
+ <!--<a href="najava.php?dom=marnet.mk" >�������� �������</a> -->
296
+ </font></strong>
297
+ </td>
298
+ </tr>
299
+ <table></td></tr></table> </td>
300
+
301
+ </table>
vendor/paquettg/php-html-parser/tests/files/small.html ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="white-stone post-row">
2
+ <div class="gs-container gs-no-gutter">
3
+ <div class="default-1-5">
4
+ <div class="post-col-left">
5
+ <p class="post-user"><font color="red">VonBurgermeister</font></p>
6
+ <div class="content-border post-avatar">
7
+ <div class="white-stone">
8
+ <a class="avatar">
9
+
10
+ <img class="user_summoner_icon" src="image.php?u=2350271&amp;dateline=1343167527" alt="VonBurgermeister's Avatar" />
11
+
12
+ </a>
13
+ </div>
14
+ </div>
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+ <p>
28
+ <font color="red"><strong>UX Designer</strong></font>
29
+
30
+ </p>
31
+ </div>
32
+ </div>
33
+ <div class="default-4-5">
34
+ <div class="post-col-right">
35
+ <div class="post-header padding-side-10 clearfix">
36
+ <!-- Post Date -->
37
+
38
+ <span>4 Weeks Ago</span>
39
+
40
+
41
+
42
+
43
+
44
+
45
+ <!-- Riot Post -->
46
+
47
+ <a id="42817067"></a>
48
+ <div class="float-right">
49
+ <span>
50
+
51
+ 99 of 100 Riot Posts
52
+
53
+ </span>
54
+
55
+ <a href="showthread.php?p=42793205#42793205" title="Previous Riot Post" od>
56
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/previous.png" class="previous_riot_post" />
57
+ </a>
58
+
59
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/logo2.png" class="riot_logo" />
60
+
61
+ <a href="showthread.php?p=43035185#43035185" title="Next Riot Post">
62
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/next.png" class="next_riot_post" />
63
+ </a>
64
+
65
+
66
+ <a href="showthread.php?p=43035185#43035185" title="">
67
+ <img src="http://d1bk7tsfygepyx.cloudfront.net/img/riot_posts/last.png" class="last_riot_post" />
68
+ </a>
69
+
70
+ </div>
71
+
72
+ </div>
73
+ <hr class="subtle-divider">
74
+
75
+ <div class="post-message">
76
+ <p><div class="quote">
77
+ <div>Quote:</div>
78
+ <div class="quote-message">
79
+
80
+ <div>
81
+ Originally Posted by <strong>Righteous Djinn</strong>
82
+
83
+ <a href="showthread.php?p=42815940#post42815940" rel="nofollow"><img class="inlineimg" src="images/buttons/viewpost.gif" border="0" alt="View Post" /></a>
84
+
85
+ </div>
86
+ <div>Are you using Design Thinking to come up with this stuff, or what?!?</div>
87
+
88
+ </div>
89
+ </div>+1 for Design Thinking</p>
90
+
91
+
92
+
93
+ </div>
94
+ <hr class="subtle-divider">
95
+
96
+ <!-- Post Footer -->
97
+ <div class="post-footer padding-side-10 clearfix">
98
+ <!-- Post Ranking -->
99
+
100
+
101
+ <span class="post-rating padding-side-10 rating-positive">+3</span>
102
+
103
+
104
+
105
+ <div class="post-footer-buttons">
106
+
107
+
108
+
109
+
110
+
111
+ </div>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </div>
116
+ </div>
117
+
vendor/paquettg/string-encode/.travis.yml ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ language: php
2
+
3
+ php:
4
+ - 5.4
5
+ - 5.5
6
+ - hhvm
7
+
8
+ install:
9
+ - composer self-update
10
+ - composer install
11
+
12
+ script:
13
+ phpunit
14
+
vendor/paquettg/string-encode/CONTRIBUTING.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PHPHtmlParser Contribution Guide
2
+
3
+ This page contains guidelines for contributing to the PHPHtmlParser package. Please review these guidelines before submitting any puLl requests to the package.
4
+
5
+ ## Pull Requests
6
+
7
+ The pull request process differs for new features and bugs. Before sending a pull request for a new feature, you should first create an issue with `[Proposal]` in the title. The proposal should describe the new feature, as well as implementation ideas. The proposal will then be reviewed and either approved or denied. Once a proposal is approved, a pull request may be created implementing the new feature. Pull requests which do not follow this guideline will be closed immediately.
8
+
9
+ Pull requests for bugs may be sent without creating any proposal issue. If you believe that you know of a solution for a bug that has been filed on Github, please leave a comment detailing your proposed fix.
10
+
11
+ ### Feature Requests
12
+
13
+ If you have an idea for a new feature you would like to see added to the package, you may create an issue on Github with `[Request]` in the title. The feature request will then be reviewed.
14
+
15
+ ## Coding Guidelines
16
+
17
+ We follow the [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) autoloading standard and take heavily from the [PSR-1](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md) coding standards. In addition to these standards, below is a list of other coding standards that should be followed:
18
+
19
+ - Class opening `{` should be on the same line as the class name.
20
+ - Function and control structure opening `{` should be on a separate line.
21
+ - Interface names are suffixed with `Interface` (`FooInterface`)
vendor/paquettg/string-encode/README.md ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ String Encode
2
+ ==========================
3
+
4
+ Version 0.1.1
5
+
6
+ String Encode is a simple PHP wrapper package to facilitate the encoding of strings in different charsets.
7
+
8
+ Install
9
+ -------
10
+
11
+ This package can be found on [packagist](https://packagist.org/packages/paquettg/stringencode) and is best loaded using [composer](http://getcomposer.org/). It does require php 5.4 or higher, so keep that in consideration.
12
+
13
+ Usage
14
+ -----
15
+
16
+ This is a really simple package so there is not much to say about it. The following is just about the only usage for this package at the moment.
17
+
18
+ ```php
19
+ use stringEncode\Encode;
20
+
21
+ $str = "Calendrier de l'avent façon Necta!"
22
+ $encode = new Encode;
23
+ $encode->detect($str);
24
+ $newstr = $encode->convert($str);
25
+ echo $newstr; // "Calendrier de l'avent façon Necta!" in UTF-8 encoding (default)
26
+ ```
27
+
28
+ As you can see, it is a very simple encoding converter.
vendor/paquettg/string-encode/composer.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "paquettg/string-encode",
3
+ "type": "library",
4
+ "description": "Facilitating the process of altering string encoding in PHP.",
5
+ "version": "0.1.1",
6
+ "keywords": ["encoding", "charset", "string"],
7
+ "homepage": "https://github.com/paquettg/string-encoder",
8
+ "license": "MIT",
9
+ "authors": [
10
+ {
11
+ "name": "Gilles Paquette",
12
+ "email": "paquettg@gmail.com",
13
+ "homepage": "http://gillespaquette.ca"
14
+ }
15
+ ],
16
+ "require": {
17
+ "php": ">=5.4"
18
+ },
19
+ "require-dev": {
20
+ "phpunit/phpunit": "3.7.*"
21
+ },
22
+ "autoload": {
23
+ "psr-0": {
24
+ "stringEncode": "src/"
25
+ }
26
+ },
27
+ "minimum-stability": "dev"
28
+ }
vendor/paquettg/string-encode/phpunit.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ |--------------------------------------------------------------------------
5
+ | Register The Composer Auto Loader
6
+ |--------------------------------------------------------------------------
7
+ |
8
+ | Composer provides a convenient, automatically generated class loader
9
+ | for our application. We just need to utilize it! We'll require it
10
+ | into the script here so that we do not have to worry about the
11
+ | loading of any our classes "manually". Feels great to relax.
12
+ |
13
+ */
14
+
15
+ require __DIR__.'/vendor/autoload.php';
16
+
17
+ /*
18
+ |--------------------------------------------------------------------------
19
+ | Set The Default Timezone
20
+ |--------------------------------------------------------------------------
21
+ |
22
+ | Here we will set the default timezone for PHP. PHP is notoriously mean
23
+ | if the timezone is not explicitly set. This will be used by each of
24
+ | the PHP date and date-time functions throughout the application.
25
+ |
26
+ */
27
+
28
+ date_default_timezone_set('UTC');
vendor/paquettg/string-encode/phpunit.xml ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <phpunit backupGlobals="false"
3
+ backupStaticAttributes="false"
4
+ bootstrap="phpunit.php"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ processIsolation="false"
10
+ stopOnFailure="false"
11
+ syntaxCheck="false"
12
+ >
13
+ <testsuites>
14
+ <testsuite name="Repository Test Suite">
15
+ <directory>./tests/</directory>
16
+ </testsuite>
17
+ </testsuites>
18
+
19
+ <filter>
20
+ <whitelist addUncoveredFilesFromWhitelist="false">
21
+ <directory suffix=".php">src</directory>
22
+ <exclude>
23
+ <directory suffix=".php">vendor</directory>
24
+ </exclude>
25
+ </whitelist>
26
+ </filter>
27
+ </phpunit>
vendor/paquettg/string-encode/src/stringEncode/Encode.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace stringEncode;
3
+
4
+ class Encode {
5
+
6
+ /**
7
+ * The encoding that the string is currently in.
8
+ *
9
+ * @var string
10
+ */
11
+ protected $from;
12
+
13
+ /**
14
+ * The encoding that we would like the string to be in.
15
+ *
16
+ * @var string
17
+ */
18
+ protected $to;
19
+
20
+ /**
21
+ * Sets the default charsets for thie package.
22
+ */
23
+ public function __construct()
24
+ {
25
+ // default from encoding
26
+ $this->from = 'CP1252';
27
+
28
+ // default to encoding
29
+ $this->to = 'UTF-8';
30
+ }
31
+
32
+ /**
33
+ * Sets the charset that we will be converting to.
34
+ *
35
+ * @param string $charset
36
+ * @chainable
37
+ */
38
+ public function to($charset)
39
+ {
40
+ $this->to = strtoupper($charset);
41
+ return $this;
42
+ }
43
+
44
+ /**
45
+ * Sets the charset that we will be converting from.
46
+ *
47
+ * @param string $charset
48
+ * @chainable
49
+ */
50
+ public function from($charset)
51
+ {
52
+ $this->from = strtoupper($charset);
53
+ }
54
+
55
+ /**
56
+ * Returns the to and from charset that we will be using.
57
+ *
58
+ * @return array
59
+ */
60
+ public function charset()
61
+ {
62
+ return [
63
+ 'from' => $this->from,
64
+ 'to' => $this->to,
65
+ ];
66
+ }
67
+
68
+ /**
69
+ * Attempts to detect the encoding of the given string from the encodingList.
70
+ *
71
+ * @param string $str
72
+ * @param array $encodingList
73
+ * @return bool
74
+ */
75
+ public function detect($str, $encodingList = ['UTF-8', 'CP1252'])
76
+ {
77
+ $charset = mb_detect_encoding($str, $encodingList);
78
+ if ($charset === false)
79
+ {
80
+ // could not detect charset
81
+ return false;
82
+ }
83
+
84
+ $this->from = $charset;
85
+ return true;
86
+ }
87
+
88
+ /**
89
+ * Attempts to convert the string to the proper charset.
90
+ *
91
+ * @return string
92
+ */
93
+ public function convert($str)
94
+ {
95
+ if ($this->from != $this->to)
96
+ {
97
+ $str = iconv($this->from, $this->to, $str);
98
+ }
99
+
100
+ if ($str === false)
101
+ {
102
+ // the convertion was a failure
103
+ throw new Exception('The convertion from "'.$this->from.'" to "'.$this->to.'" was a failure.');
104
+ }
105
+
106
+ // deal with BOM issue for utf-8 text
107
+ if ($this->to == 'UTF-8')
108
+ {
109
+ if (substr($str, 0, 3) == "\xef\xbb\xbf")
110
+ {
111
+ $str = substr($str, 3);
112
+ }
113
+ if (substr($str, -3, 3) == "\xef\xbb\xbf")
114
+ {
115
+ $str = substr($str, 0, -3);
116
+ }
117
+ }
118
+
119
+ return $str;
120
+ }
121
+ }
vendor/paquettg/string-encode/src/stringEncode/Exception.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ namespace stringEncode;
3
+
4
+ class Exception extends \Exception {}
vendor/paquettg/string-encode/tests/EncodeTest.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ use stringEncode\Encode;
4
+
5
+ class ContentTest extends PHPUnit_Framework_TestCase {
6
+
7
+ public function testTo()
8
+ {
9
+ $encode = new Encode;
10
+ $encode->to('ISO-8859-1');
11
+ $this->assertEquals('ISO-8859-1', $encode->charset()['to']);
12
+ }
13
+
14
+ public function testFrom()
15
+ {
16
+ $encode = new Encode;
17
+ $encode->from('ISO-8859-1');
18
+ $this->assertEquals('ISO-8859-1', $encode->charset()['from']);
19
+ }
20
+
21
+ public function testDetect()
22
+ {
23
+ $encode = new Encode;
24
+ $encode->detect('Calendrier de l\'avent façon Necta!');
25
+ $this->assertEquals('UTF-8', $encode->charset()['from']);
26
+ }
27
+
28
+ }